#include "parse/scripting.h" #ifdef USE_LUA #include #include "parse/lua.h" #include "graphics/2d.h" #include "ship/ship.h" #include "Ship/shipfx.h" #include "io/mouse.h" #include "gamesequence/gamesequence.h" #include "globalincs/pstypes.h" //*************************Lua funcs************************* int lua_parse_args(lua_State *L, char *fmt, ...); int lua_return_args(lua_State *L, char* fmt, ...); int script_remove_lib(lua_State *L, char *name); void lua_stackdump(lua_State *L); //*************************Lua helpers************************* //Function helper helper //Stores data about functions struct lua_func_hh { char *Name; lua_CFunction Function; char *Description; char *Arguments; char *ReturnValues; }; class lua_lib_h { /* friend class lua_lib; friend class lua_obj_h; friend int script_state::CreateLuaState(); friend void output_lib_meta(FILE *fp, lua_lib_h *lib); friend void script_state::OutputLuaMeta(FILE *fp); */ //private: public: char *Name; char *Description; std::vector Functions; public: lua_lib_h(char *in_name, char *in_desc){Name = in_name; Description = in_desc;} }; std::vector lua_Libraries; std::vector lua_Objects; //Library class //This is what you define a variable of to make new libraryes class lua_lib { private: int lib_idx; public: lua_lib(char *in_name, char *in_desc){ lua_Libraries.push_back(lua_lib_h(in_name, in_desc)); lib_idx = lua_Libraries.size()-1; } void AddFunc(lua_func_hh *f){lua_Libraries[lib_idx].Functions.push_back(*f);} }; //Used with the args functions to check a function type //You should really use LUA_CVAR though struct script_lua_opdata { char *meta; void **buf; script_lua_opdata(char* in_meta, void** in_buf){meta=in_meta; buf=in_buf;} }; struct script_lua_odata { char *meta; void *buf; int size; script_lua_odata(char *in_meta, void *in_buf, int in_size){meta=in_meta;buf=in_buf;size=in_size;} }; //Lua_obj helper class //Because of some STUPID limitation with templates, I couldn't pass //a lua_obj object as a reference and then execute AddFunc() //This class is a hack via derivation to make it work -C class lua_obj_h { public: int obj_idx; public: lua_obj_h(char *in_name, char *in_desc) { lua_Objects.push_back(lua_lib_h(in_name, in_desc)); obj_idx = lua_Objects.size()-1; } void AddFunc(lua_func_hh *f){lua_Objects[obj_idx].Functions.push_back(*f);} }; //Function helper class //Lets us add functions via its constructor class lua_func_h { public: lua_func_h(char *name, lua_CFunction func, lua_lib &lib, char *desc, char *args, char *retvals) { lua_func_hh f; f.Name = name; f.Function = func; f.Description = desc; f.Arguments = args; f.ReturnValues = retvals; lib.AddFunc(&f); } lua_func_h(char *name, lua_CFunction func, lua_obj_h &obj, char *desc, char *args, char *retvals) { lua_func_hh f; f.Name = name; f.Function = func; f.Description = desc; f.Arguments = args; f.ReturnValues = retvals; obj.AddFunc(&f); } }; //Object class //This is what you define a variable of to make new objects template class lua_obj : public lua_obj_h { public: lua_obj(char*in_name, char*in_desc):lua_obj_h(in_name, in_desc){}; //StoreType *Create(lua_State *L){StoreType *ptr = (StoreType*)LUA_NEW_OBJ(L, meta, StoreType); return ptr;} script_lua_odata Return(StoreType *obj){return script_lua_odata(lua_Objects[obj_idx].Name, obj, sizeof(StoreType));} script_lua_odata Parse(StoreType *ptr){return script_lua_odata(lua_Objects[obj_idx].Name, ptr, sizeof(StoreType));} script_lua_opdata ParsePtr(StoreType **ptr){return script_lua_opdata(lua_Objects[obj_idx].Name, ptr);} }; //Function macro //This is what you call to make new functions #define LUA_FUNC(name, objlib, desc, args, retvals) \ static int lua_##objlib##_##name(lua_State *L); \ lua_func_h lua_##objlib##_##name##_h(#name, lua_##objlib##_##name, objlib, desc, args, retvals); \ static int lua_##objlib##_##name(lua_State *L) /* //Callback typedef #define SCRIPT_LUA_CALLBACK static int //Function entry for a library typedef struct script_lua_func_list { const char *name; lua_CFunction func; const char *description; const char *args; const char *retvals; } script_lua_func_list; //Function entry for an object typedef struct script_lua_obj_func_list { const char *name; lua_CFunction func; const char *description; const char *args; const char *retvals; } script_lua_obj_func_list; //Object entry for a library typedef struct script_lua_obj_list { const char *object_name; const script_lua_obj_func_list *object_funcs; const char *description; }script_lua_obj_list; //Library entry typedef struct script_lua_lib_list { const char *library_name; const script_lua_func_list *library_funcs; const script_lua_obj_list *library_objects; const char *description; }script_lua_lib_list; //LUA_NEW_OBJ(lua_State, object name, object struct) #define LUA_NEW_OBJ(L,n,s) \ (s *) lua_newuserdata(L, sizeof(s)); \ luaL_getmetatable(L, n); \ lua_setmetatable(L, -2) template class lua_cvar { char meta[NAME_LENGTH]; public: lua_cvar(char *in_meta){sprintf(meta, "fs2.%s", in_meta);} char *GetName(){return meta;} //StoreType *Create(lua_State *L){StoreType *ptr = (StoreType*)LUA_NEW_OBJ(L, meta, StoreType); return ptr;} script_lua_odata Return(StoreType *obj){return script_lua_odata(meta, obj, sizeof(StoreType));} script_lua_odata Parse(StoreType *ptr){return script_lua_odata(meta, ptr, sizeof(StoreType));} script_lua_opdata ParsePtr(StoreType **ptr){return script_lua_opdata(meta, ptr);} }; */ /*struct script_lua_pdata { char *meta; void *buf; script_lua_pdata(char* in_meta, void* in_buf){meta=in_meta;buf=in_buf;} };*/ //LUA_CVAR(name, pointer) //Call this with lua_parse_args to store the pointer to //a specific set of userdata in a pointer. //-----EX: //lua_parse_args(L, "u", LUA_CVAR("ship", &lua_ship)) #define LUA_CVAR(n, p) script_lua_udata(n, (void**)&p) //#define LUA_PTR(n, p) script_lua_pdata(n, (void*)p) //*************************Lua return values************************* #define LUA_RETURN_NOTHING 0 #define LUA_RETURN_OBJECT 1 //*************************Lua defines************************* //These are the various types of operators you can //set in Lua. Define these in script_lua_obj_func_list #define LUA_OPER_METHOD "__index" #define LUA_OPER_ADDITION "__add" #define LUA_OPER_SUBTRACTION "__sub" #define LUA_OPER_MULTIPLICATION "__mult" #define LUA_OPER_DIVISION "__div" #define LUA_OPER_POWER "__pow" #define LUA_OPER_UNARY "__unm" #define LUA_OPER_CONCATENATION "__concat" #define LUA_OPER_EQUALTO "__eq" #define LUA_OPER_LESSTHAN "__lt" #define LUA_OPER_LESSTHANEQUALTO "__le" #define LUA_OPER_INDEX "__index" #define LUA_OPER_NEWINDEX "__newindex" #define LUA_OPER_CALL "__call" #define LUA_OPER_TOSTRING "__tostring" //*************************General Functions************************* //WMC - This doesn't work. int script_remove_lib(lua_State *L, char *name) { lua_pushstring(L, name); lua_gettable(L, LUA_GLOBALSINDEX); if(lua_istable(L, -1)) { lua_pop(L, -1); return 1; } return 0; } void lua_stackdump(lua_State *L, char *stackdump) { char buf[512]; int stacksize = lua_gettop(L); //Lua temps double d; int b; char *s; void *v; lua_State *ls; for(int argnum = 1; argnum <= stacksize; argnum++) { int type = lua_type(L, argnum); sprintf(buf, "\r\n%d: ", argnum); strcat(stackdump, buf); switch(type) { case LUA_TNIL: strcat(stackdump, "NIL"); break; case LUA_TNUMBER: d = lua_tonumber(L, argnum); sprintf(buf, "Number [%f]",d); strcat(stackdump, buf); break; case LUA_TBOOLEAN: b = lua_toboolean(L, argnum); sprintf(buf, "Boolean [%d]",b); strcat(stackdump, buf); break; case LUA_TSTRING: s = (char *)lua_tostring(L, argnum); sprintf(buf, "String [%s]",s); strcat(stackdump, buf); break; case LUA_TTABLE: strcat(stackdump, "Table"); break; case LUA_TFUNCTION: strcat(stackdump, "Function"); break; case LUA_TUSERDATA: v = lua_touserdata(L, argnum); sprintf(buf, "Userdata [%d]", v); strcat(stackdump, buf); break; case LUA_TTHREAD: ls = lua_tothread(L, argnum); sprintf(buf, "Thread [%d]", ls); strcat(stackdump, buf); break; case LUA_TLIGHTUSERDATA: v = lua_touserdata(L, argnum); sprintf(buf, "Light userdata [%d]", v); strcat(stackdump, buf); break; default: sprintf(buf, ": %s (%d) (%s)", lua_typename(L, type), lua_tonumber(L, argnum), lua_tostring(L, argnum)); strcat(stackdump, buf); break; } } } //lua_parse_args(state, arguments, variables) //---------------------------------------------- //based on "Programming in Lua" // //Parses arguments from string to variables given //a '|' divides required and optional arguments. //Returns 0 if a required argument is invalid, //or there are too few arguments actually passed int lua_parse_args(lua_State *L, char *fmt, ...) { //Check that we have all the arguments that we need //If we don't, return 0 int needed_args = strlen(fmt); int total_args = lua_gettop(L); if(strchr(fmt, '|') != NULL) { needed_args = strchr(fmt, '|') - fmt; } if(total_args < needed_args) { Warning(LOCATION, "Not enough arguments for function"); return 0; } //Start throught va_list vl; int nargs; //Are we parsing optional args yet? bool optional_args = false; va_start(vl, fmt); nargs = 1; while(*fmt && nargs <= total_args) { //Skip functions; I assume these are being used to return args while(lua_type(L, nargs) == LUA_TFUNCTION && nargs <= total_args) nargs++; switch(*fmt++) { case 'b': if(lua_isboolean(L, nargs)) { *va_arg(vl, bool*) = lua_toboolean(L, nargs) > 0 ? true : false; } else { Warning(LOCATION, "Argument %d is an invalid type; boolean expected", nargs); if(!optional_args) return 0; } break; case 'd': if(lua_isnumber(L, nargs)) { *va_arg(vl, double*) = (double)lua_tonumber(L, nargs); } else { Warning(LOCATION, "Argument %d is an invalid type; float expected", nargs); if(!optional_args) return 0; } break; case 'f': if(lua_isnumber(L, nargs)) { *va_arg(vl, float*) = (float)lua_tonumber(L, nargs); } else { Warning(LOCATION, "Argument %d is an invalid type; float expected", nargs); if(!optional_args) return 0; } break; case 'i': if(lua_isnumber(L, nargs)) { *va_arg(vl, int*) = (int)lua_tonumber(L, nargs); } else { Warning(LOCATION, "Argument %d is an invalid type; int expected", nargs); if(!optional_args) return 0; } break; case 's': if(lua_isstring(L, nargs)) { *va_arg(vl, const char **) = lua_tostring(L, nargs); } else { Warning(LOCATION, "Argument %d is an invalid type; string expected", nargs); if(!optional_args) return 0; } break; case 'o': if(lua_isuserdata(L, nargs)) { script_lua_odata od = va_arg(vl, script_lua_odata); void *ptr = luaL_checkudata(L, nargs, od.meta); if(ptr == NULL) { Warning(LOCATION, "Argument %d is the wrong type of userdata; %s expected", nargs, od.meta); } memcpy(od.buf, ptr, od.size); } else { Warning(LOCATION, "Argument %d is an invalid type %d; type '%s' expected", nargs, lua_type(L, nargs), va_arg(vl, script_lua_odata).meta); if(!optional_args) return 0; } break; case 'p': if(lua_isuserdata(L, nargs)) { script_lua_opdata pd = va_arg(vl, script_lua_opdata); (*pd.buf) = luaL_checkudata(L, nargs, pd.meta); if((*pd.buf) == NULL) { Warning(LOCATION, "Argument %d is the wrong type of userdata; %s expected", nargs, pd.meta); } } else { Warning(LOCATION, "Argument %d is an invalid type %d; type '%s' expected", nargs, lua_type(L, nargs), va_arg(vl, script_lua_opdata).meta); if(!optional_args) return 0; } break; case '|': nargs--; //cancel out the nargs++ at the end optional_args = true; break; default: Error(LOCATION, "Bad character passed to lua_parse_args; (%c)", *(fmt-1)); break; } nargs++; } va_end(vl); return nargs; } int lua_return_args(lua_State *L, char *fmt, ...) { //Start throught va_list vl; int nargs; va_start(vl, fmt); nargs = 0; while(*fmt) { switch(*fmt++) { case 'b': lua_pushboolean(L, va_arg(vl, bool) ? 1 : 0); break; case 'd': lua_pushnumber(L, va_arg(vl, double)); break; case 'f': lua_pushnumber(L, va_arg(vl, double)); break; case 'i': lua_pushnumber(L, va_arg(vl, int)); break; case 's': lua_pushstring(L, va_arg(vl, char *)); break; case 'o': //Just let nargs increment; it should already be on the stack { script_lua_odata od = va_arg(vl, script_lua_odata); void *newod = (void*)lua_newuserdata(L, sizeof(void*)); luaL_getmetatable(L, od.meta); lua_setmetatable(L, -2); memcpy(newod, od.buf, od.size); break; } default: Error(LOCATION, "Bad character passed to lua_return_args; (%c)", *fmt); } nargs++; } va_end(vl); return nargs; } //*************************Object #defines************************* //While you don't _need_ to add object defines here, it's a good idea //so you can catch misspellings and make sure the name isn't taken already //note that all object names should start with "fs2." to prevent conflicts // //IMPORTANT: Before you can use a type, it MUST be defined in a library // that exists in the current state /* static lua_cvar l_lvec("lvec"); static lua_cvar l_wvec("wvec"); static lua_cvar l_model("model"); static lua_cvar l_ship_info("ship_info"); static lua_cvar l_ship("ship"); */ //**********CLASS: Shipclass lua_obj l_Shipclass("shipclass", "Ship class object"); extern int ships_inited; LUA_FUNC(getName, l_Shipclass, "Gets ship class name", NULL, "Name (string)") { int idx; if(!lua_parse_args(L, "o", l_Shipclass.Parse(&idx))) return LUA_RETURN_NOTHING; if(idx < 0 || idx > Num_ship_classes) return LUA_RETURN_NOTHING; return lua_return_args(L, "s", Ship_info[idx].name); } LUA_FUNC(getShortName, l_Shipclass, "Gets ship class short name", NULL, "Short name (string)") { int idx; if(!lua_parse_args(L, "o", l_Shipclass.Parse(&idx))) return LUA_RETURN_NOTHING; if(idx < 0 || idx > Num_ship_classes) return LUA_RETURN_NOTHING; return lua_return_args(L, "s", Ship_info[idx].short_name); } LUA_FUNC(getHitpoints, l_Shipclass, "Gets ship class hitpoints", NULL, "Hitpoints (number)") { int idx; if(!lua_parse_args(L, "o", l_Shipclass.Parse(&idx))) return LUA_RETURN_NOTHING; if(idx < 0 || idx > Num_ship_classes) return LUA_RETURN_NOTHING; return lua_return_args(L, "f", Ship_info[idx].max_hull_strength); } //**********CLASS: Ship lua_obj l_Ship("ship", "Ship object"); //Helper function int lua_ship_get_idx(lua_State *L, int *idx) { if(!lua_parse_args(L, "o", l_Ship.Parse(idx))) return 0; *idx = ship_get_by_signature(*idx); if(*idx < 0) return 0; return 1; } LUA_FUNC(getName, l_Ship, "Gets ship name", NULL, "ship name (string)") { int idx; if(!lua_ship_get_idx(L, &idx)) return LUA_RETURN_NOTHING; return lua_return_args(L, "s", Ships[idx].ship_name); } LUA_FUNC(getHitpoints, l_Ship, "Gets ship hull max", NULL, "max hull hitpoints (number)") { int idx; if(!lua_ship_get_idx(L, &idx)) return LUA_RETURN_NOTHING; return lua_return_args(L, "f", Ship_info[Ships[idx].ship_info_index].max_hull_strength); } LUA_FUNC(getHitpointsLeft, l_Ship, "Gets ship hull", NULL, "Current hull hitpoints (number)") { int idx; if(!lua_ship_get_idx(L, &idx)) return LUA_RETURN_NOTHING; return lua_return_args(L, "f", Objects[Ships[idx].objnum].hull_strength); } LUA_FUNC(getClass, l_Ship, "Gets ship class handle", NULL, "Ship class handle (shipclass)") { int idx; if(!lua_ship_get_idx(L, &idx)) return LUA_RETURN_NOTHING; return lua_return_args(L, "o", l_Shipclass.Return(&Objects[Ships[idx].objnum].signature)); } LUA_FUNC(warpIn, l_Ship, "Warps ship in", NULL, NULL) { int idx; if(!lua_ship_get_idx(L, &idx)) return LUA_RETURN_NOTHING; shipfx_warpin_start(&Objects[Ships[idx].objnum]); return LUA_RETURN_NOTHING; } LUA_FUNC(warpOut, l_Ship, "Warps ship out", NULL, NULL) { int idx; if(!lua_ship_get_idx(L, &idx)) return LUA_RETURN_NOTHING; shipfx_warpout_start(&Objects[Ships[idx].objnum]); return LUA_RETURN_NOTHING; } //**********LIBRARY: Mission lua_lib l_Mission("mn", "Mission library"); LUA_FUNC(getShip, l_Mission, "Gets ship object", "Ship name", "Ship object") { char *name; if(!lua_parse_args(L, "s", &name)) return 0; int idx = ship_name_lookup(name); if(idx < 0) { return LUA_RETURN_NOTHING; } return lua_return_args(L, "o", l_Shipclass.Return(&Objects[Ships[idx].objnum].signature)); } LUA_FUNC(getNumEscortShips, l_Mission, "Gets escort ship", NULL, "Ship object") { return lua_return_args(L, "i", hud_escort_num_ships_on_list()); } LUA_FUNC(getEscortShip, l_Mission, "Gets escort ship", "Escort index", "Ship object") { int idx; if(!lua_parse_args(L, "i", &idx)) return 0; if(idx < 0) return LUA_RETURN_NOTHING; idx = hud_escort_return_objnum(idx); if(idx < 0) return LUA_RETURN_NOTHING; return lua_return_args(L, "o", l_Ship.Return(&Objects[idx].signature)); } //**********LIBRARY: Tables lua_lib l_Tables("tb", "Tables library"); LUA_FUNC(getNumShipClasses, l_Tables, "Gets number of ship classes", NULL, "Number") { if(!ships_inited) return lua_return_args(L, "i", 0); //No ships loaded...should be 0 return lua_return_args(L, "i", Num_ship_classes); } LUA_FUNC(getShipClassByIndex, l_Tables, "Gets ship class by index", "Class index", "Shipclass object") { if(!ships_inited) return LUA_RETURN_NOTHING; int idx; if(!lua_parse_args(L, "i", &idx)) return 0; if(idx < 0 || idx > Num_ship_classes) { return LUA_RETURN_NOTHING; } return lua_return_args(L, "o", l_Shipclass.Return(&idx)); } LUA_FUNC(getShipClass, l_Tables, "Gets ship class", "Class name", "Shipclass object") { if(!ships_inited) return LUA_RETURN_NOTHING; char *name; if(!lua_parse_args(L, "s", &name)) return 0; int idx = ship_info_lookup(name); if(idx < 0) { return LUA_RETURN_NOTHING; } return lua_return_args(L, "o", l_Shipclass.Return(&idx)); } //**********LIBRARY: Mouse lua_lib l_Mouse("ms", "Mouse library"); extern int mouse_inited; LUA_FUNC(getX, l_Mouse, "Gets Mouse X pos", "[Unscale]", "X pos (Number)") { if(!mouse_inited) return LUA_RETURN_NOTHING; int x; bool u = false; lua_parse_args(L, "b", &u); if(u) mouse_get_pos_unscaled(&x, NULL); else mouse_get_pos(&x, NULL); return lua_return_args(L, "i", x); } LUA_FUNC(getY, l_Mouse, "Gets Mouse Y pos", "[Unscale]", "Y pos (Number)") { if(!mouse_inited) return LUA_RETURN_NOTHING; int y; bool u = false; lua_parse_args(L, "b", &u); if(u) mouse_get_pos_unscaled(NULL, &y); else mouse_get_pos(NULL, &y); return lua_return_args(L, "i", y); } LUA_FUNC(isButtonDown, l_Mouse, "Returns whether the specified mouse buttons are up or down", "{Left, Right, or Middle}, [...], [...]", "Whether specified buttons are pressed (Boolean)") { if(!mouse_inited) return LUA_RETURN_NOTHING; char *sa[3] = {NULL, NULL, NULL}; lua_parse_args(L, "s|ss", &sa[0], &sa[1], &sa[2]); //Like a snake! bool rtn = false; int check_flags = 0; for(int i = 0; i < 3; i++) { if(sa[i] == NULL) break; if(!stricmp(sa[i], "Left")) check_flags |= MOUSE_LEFT_BUTTON; else if(!stricmp(sa[i], "Middle")) check_flags |= MOUSE_MIDDLE_BUTTON; else if(!stricmp(sa[i], "Right")) check_flags |= MOUSE_RIGHT_BUTTON; } if(mouse_down(check_flags)) rtn = true; return lua_return_args(L, "b", rtn); } LUA_FUNC(setCursorImage, l_Mouse, "Sets mouse cursor image, and allows you to lock/unlock the image. (A locked cursor may only be changed with the unlock parameter)", "Image filename w/o extension, [Lock,Unlock]", "Y pos (Number)") { if(!mouse_inited || !Gr_inited) return LUA_RETURN_NOTHING; char *s = NULL; char *u = NULL; if(!lua_parse_args(L, "s|s", &s, &u)) return LUA_RETURN_NOTHING; int ul = 0; if(u != NULL) { if(!stricmp("Lock", u)) ul = GR_CURSOR_LOCK; else if(!stricmp("Unlock", u)) ul = GR_CURSOR_UNLOCK; } gr_set_cursor_bitmap(bm_load(s), ul); return LUA_RETURN_NOTHING; } LUA_FUNC(setMouseHidden, l_Mouse, "Shows or hides mouse cursor", "True to hide mouse, false to show it", NULL) { if(!mouse_inited) return LUA_RETURN_NOTHING; bool b = false; lua_parse_args(L, "b", &b); if(b) Mouse_hidden = 1; else Mouse_hidden = 0; return LUA_RETURN_NOTHING; } //**********LIBRARY: Graphics lua_lib l_Graphics("gr", "Graphics Library"); LUA_FUNC(getScreenWidth, l_Graphics, "Gets screen width", NULL, "Width in pixels (Number)") { if(!Gr_inited) return 0; return lua_return_args(L, "i", gr_screen.max_w); } LUA_FUNC(getScreenHeight, l_Graphics, "Gets screen height", NULL, "Height in pixels (Number)") { if(!Gr_inited) return 0; return lua_return_args(L, "i", gr_screen.max_h); } LUA_FUNC(drawText, l_Graphics, "Draws a string", "x, y, String, [Resize]", NULL) { if(!Gr_inited) return 0; int x,y; char *s; bool r=true; if(!lua_parse_args(L, "iis|b", &x, &y, &s, &r)) return LUA_RETURN_NOTHING; gr_string(x,y,s,r); return LUA_RETURN_NOTHING; } LUA_FUNC(setColor, l_Graphics, "Sets 2D drawing color", "Red, Green, Blue, [alpha]", NULL) { if(!Gr_inited) return 0; int r,g,b,a=255; if(!lua_parse_args(L, "iii|i", &r, &g, &b, &a)) return 0; color ac; gr_init_alphacolor(&ac,r,g,b,a); gr_set_color_fast(&ac); return 0; } LUA_FUNC(setFont, l_Graphics, "Sets current font", "Font index", NULL) { if(!Gr_inited) return 0; int fn; if(!lua_parse_args(L, "i", &fn)) return 0; gr_set_font(fn); return 0; } LUA_FUNC(drawPixel, l_Graphics, "Sets pixel to current color", "x, y, [Resize]", NULL) { if(!Gr_inited) return 0; int x,y; bool r=true; if(!lua_parse_args(L, "ii|b", &x, &y, &r)) return 0; gr_pixel(x,y,r); return 0; } LUA_FUNC(drawLine, l_Graphics, "Draws a line with the current color", "x1, y1, x2, y2, [Resize]", NULL) { if(!Gr_inited) return 0; int x1,y1,x2,y2; bool r=true; if(!lua_parse_args(L, "iiii|b", &x1, &y1, &x2, &y2, &r)) return 0; gr_line(x1,y1,x2,y2,r); return 0; } LUA_FUNC(drawGradientLine, l_Graphics, "Draws a line that steadily fades out", "x1, y1, x2, y2, [Resize]", NULL) { if(!Gr_inited) return 0; int x1,y1,x2,y2; bool r=true; if(!lua_parse_args(L, "iiii|b", &x1, &y1, &x2, &y2, &r)) return 0; gr_gradient(x1,y1,x2,y2,r); return 0; } LUA_FUNC(drawCircle, l_Graphics, "Draws a circle", "x, y, Radius, [Resize]", NULL) { if(!Gr_inited) return 0; int x,y,ra; bool r=true; if(!lua_parse_args(L, "iii|b", &x,&y,&ra,&r)) return 0; gr_circle(x,y, ra, r); return 0; } LUA_FUNC(drawCurve, l_Graphics, "Draws a curve", "x, y, Radius, Direction", NULL) { if(!Gr_inited) return 0; int x,y,ra,d; if(!lua_parse_args(L, "iiii|b", &x,&y,&ra,&d)) return 0; gr_curve(x,y,ra,d); return 0; } LUA_FUNC(drawImage, l_Graphics, "Draws an image", "x, y, Image name, [Resize]", NULL) { if(!Gr_inited) return 0; int x,y; char *s; bool r = true; if(!lua_parse_args(L, "iis|b", &x,&y,&s,&r)) return 0; int idx = bm_load(s); gr_set_bitmap(idx); gr_bitmap(x, y, r); return 0; } LUA_FUNC(flashScreen, l_Graphics, "Flashes the screen", "Red, Green, Blue", NULL) { if(!Gr_inited) return 0; int r,g,b; if(!lua_parse_args(L, "iii", &r, &g, &b)) return 0; gr_flash(r,g,b); return 0; } //*************************Libraries************************* /* //**********LIBRARY: Base //*****CLASS: (l)vec SCRIPT_LUA_CALLBACK lua_fs2_lvec(lua_State *L) { vec3d v3 = vmd_zero_vector; lua_parse_args(L, "|fff", &v3.xyz.x, &v3.xyz.y, &v3.xyz.z); return lua_return_args(L, "o", l_lvec.Return(&v3)); } SCRIPT_LUA_CALLBACK lua_fs2_vec__addition(lua_State *L) { vec3d v3a, v3b, v3r; if(!lua_parse_args(L, "oo", l_lvec.Parse(&v3a), l_lvec.Parse(&v3b))) return 0; vm_vec_add(&v3r, &v3a, &v3b); return lua_return_args(L, "o", l_lvec.Return(&v3r)); } SCRIPT_LUA_CALLBACK lua_fs2_vec__subtraction(lua_State *L) { vec3d v3a, v3b, v3r; if(!lua_parse_args(L, "oo", l_lvec.Parse(&v3a), l_lvec.Parse(&v3b))) return 0; vm_vec_sub(&v3r, &v3a, &v3b); return lua_return_args(L, "o", l_lvec.Return(&v3r)); } SCRIPT_LUA_CALLBACK lua_fs2_vec__multiplication(lua_State *L) { vec3d v3a, v3b, v3r; float f; if(lua_parse_args(L, "of", l_lvec.Parse(&v3a), &f)) { vm_vec_copy_scale(&v3r, &v3a, f); return lua_return_args(L, "o", l_lvec.Return(&v3r)); } else if(lua_parse_args(L, "oo", l_lvec.Parse(&v3a), l_lvec.Parse(&v3b))) { v3r.xyz.x = v3a.xyz.x * v3b.xyz.x; v3r.xyz.y = v3a.xyz.y * v3b.xyz.y; v3r.xyz.z = v3a.xyz.z * v3b.xyz.z; return lua_return_args(L, "o", l_lvec.Return(&v3r)); } //Neither is valid... return LUA_RETURN_NOTHING; } SCRIPT_LUA_CALLBACK lua_fs2_vec__tostring(lua_State *L) { vec3d v3p; if(!lua_parse_args(L, "o", l_lvec.Parse(&v3p))) return 0; char buf[32]; sprintf(buf, "(%f, %f, %f)", v3p.xyz.x, v3p.xyz.y, v3p.xyz.z); return lua_return_args(L, "s", buf); } SCRIPT_LUA_CALLBACK lua_fs2_vec__index(lua_State *L) { vec3d v3p; int idx=0; if(!lua_parse_args(L, "o|i", l_lvec.Parse(&v3p), &idx)) return 0; if(idx < 0 || idx > 2) { return 0; } return lua_return_args(L, "f", v3p.a1d[idx]); } SCRIPT_LUA_CALLBACK lua_fs2_vec_print(lua_State *L) { vec3d v3p; int idx=0; if(!lua_parse_args(L, "o|i", l_lvec.Parse(&v3p), &idx)) return 0; if(idx < 0 || idx > 2) { return 0; } //Error(LOCATION, "%f %f %f", v3p.xyz.x, v3p.xyz.y, v3p.xyz.z); return 0; } static const script_lua_obj_func_list lua_fs2_lvec_funcs[] = { {LUA_OPER_ADDITION, lua_fs2_vec__addition, "Adds two vectors"}, {LUA_OPER_SUBTRACTION, lua_fs2_vec__subtraction, "Subtracts one vector from another"}, {LUA_OPER_MULTIPLICATION, lua_fs2_vec__multiplication, "Multiplies two vectors, or a vector times a number"}, {LUA_OPER_TOSTRING, lua_fs2_vec__tostring, "Converts vector to string"}, {"print", lua_fs2_vec_print, "Prints a vector"}, //{LUA_OPER_INDEX, lua_fs2_vec__index, "Returns index into vector"}, {SCRIPT_END_LIST}, }; //*****CLASS: wvec SCRIPT_LUA_CALLBACK lua_fs2_wvec(lua_State *L) { vec3d v3 = vmd_zero_vector; lua_parse_args(L, "|fff", &v3.xyz.x, &v3.xyz.y, &v3.xyz.z); vec3d v3p; v3p.xyz.x = v3.xyz.x; v3p.xyz.y = v3.xyz.y; v3p.xyz.z = v3.xyz.z; return lua_return_args(L, "o", l_wvec.Return(&v3p)); } static const script_lua_obj_func_list lua_fs2_wvec_funcs[] = { {LUA_OPER_ADDITION, lua_fs2_vec__addition, "Adds two vectors"}, {LUA_OPER_SUBTRACTION, lua_fs2_vec__subtraction, "Subtracts one vector from another"}, {LUA_OPER_MULTIPLICATION, lua_fs2_vec__multiplication, "Multiplies two vectors, or a vector times a number"}, {LUA_OPER_TOSTRING, lua_fs2_vec__tostring, "Converts vector to string"}, //{LUA_OPER_INDEX, lua_fs2_vec__index, "Returns index into vector"}, {SCRIPT_END_LIST}, }; //*****LIBRARY CLASSES static const script_lua_obj_list lua_base_lib_obj[] = { {l_lvec.GetName(), lua_fs2_lvec_funcs, "Local vector"}, {l_wvec.GetName(), lua_fs2_wvec_funcs, "World vector"}, {SCRIPT_END_LIST}, }; //*****LIBRARY FUNCTIONS SCRIPT_LUA_CALLBACK lua_fs2_print(lua_State *L) { Error(LOCATION, "LUA: %s", lua_tostring(L, -1)); return 0; } SCRIPT_LUA_CALLBACK lua_fs2_error(lua_State *L) { Error(LOCATION, "LUA ERROR: %s", lua_tostring(L, -1)); return 0; } SCRIPT_LUA_CALLBACK lua_fs2_getState(lua_State *L) { int depth = 0; lua_parse_args(L, "|i", &depth); return lua_return_args(L, "s", GS_state_text[gameseq_get_state(depth)]); } static const script_lua_func_list lua_base_lib[] = { {"lvec", lua_fs2_lvec, "Creates a new local vector: (x, y, z)"}, {"wvec", lua_fs2_wvec, "Creates a new world vector: (x, y, z)"}, {"print", lua_fs2_print, "Displays output"}, {"error", lua_fs2_error, "Causes an error"}, {"getState", lua_fs2_getState, "Returns the current FS2 state string"}, {SCRIPT_END_LIST}, }; //**********LIBRARY: Mission (msn) SCRIPT_LUA_CALLBACK lua_msn_getShipInfo(lua_State *L) { char *ship_name = NULL; if(!lua_parse_args(L, "s", &ship_name)) return 0; int idx = ship_info_lookup(ship_name); if(idx < 0) return 0; ship_info *sip = &Ship_info[idx]; return lua_return_args(L, "o", l_ship_info.Return(&sip)); } SCRIPT_LUA_CALLBACK lua_msn_ShipInfo_print(lua_State *L) { ship_info *sip; if(!lua_parse_args(L, "o", l_ship_info.Parse(&sip))) return 0; //Error(LOCATION, "%s", sip->name); return 0; } SCRIPT_LUA_CALLBACK lua_msn_newShip(lua_State *L) { char *ship_name = NULL; char *class_name = NULL; vec3d pos; angles ang = {0,0,0}; if(!lua_parse_args(L, "ssfff|fff", &ship_name, &class_name, &pos.xyz.x, &pos.xyz.y, &pos.xyz.z, &ang.p, &ang.b, &ang.h)) return 0; //New matrix matrix ori = IDENTITY_MATRIX; vm_angles_2_matrix(&ori, &ang); //Find the class index int si_idx = ship_info_lookup(class_name); if(si_idx < 0) { //couldn't find it return LUA_RETURN_NOTHING; } //Create the ship int s_idx = ship_create(&ori, &pos, si_idx, ship_name); //Make the lua ship object, if the ship was created if(s_idx > -1) { //Make the lua ship object and set the ptr to NULL ship *shipp = &Ships[s_idx]; return lua_return_args(L, "o", l_ship.Return(&shipp)); } return LUA_RETURN_NOTHING; } SCRIPT_LUA_CALLBACK lua_msn_ship_setSpeed(lua_State *L) { ship *shipp = NULL; vec3d vel; if(!lua_parse_args(L, "offf", l_ship.Parse(&shipp), &vel.xyz.x, &vel.xyz.y, &vel.xyz.z)) return LUA_RETURN_NOTHING; //Set the speed Objects[shipp->objnum].phys_info.vel = vel; //We're done! return LUA_RETURN_NOTHING; } SCRIPT_LUA_CALLBACK lua_msn_ship_setName(lua_State *L) { ship *shipp = NULL; char *name = NULL; if(!lua_parse_args(L, "os", l_ship.Parse(&shipp), &name)) return LUA_RETURN_NOTHING; //Set the name if(strlen(name)) { strcpy(shipp->ship_name, name); } else { sprintf(shipp->ship_name, "Ship %d", SHIP_INDEX(shipp)); } //We're done! return LUA_RETURN_NOTHING; } SCRIPT_LUA_CALLBACK lua_msn_ship_getTarget(lua_State *L) { ship *shipp = NULL; if(!lua_parse_args(L, "o", l_ship.Parse(&shipp))) return 0; if(shipp->ai_index != -1) { ai_info *aip= &Ai_info[shipp->ai_index]; if(aip->target_objnum && Objects[aip->target_objnum].type == OBJ_SHIP) { ship *tshipp = &Ships[Objects[aip->target_objnum].instance]; return lua_return_args(L, "o", l_ship.Return(&tshipp)); } } //We're done! return 0; } static const script_lua_obj_func_list lua_msn_shipinfo_funcs[] = { {"print",lua_msn_ShipInfo_print, "Prints ship name"}, {SCRIPT_END_LIST}, }; static const script_lua_obj_func_list lua_msn_ship_funcs[] = { {"setSpeed", lua_msn_ship_setSpeed, "Sets ship speed: (x speed, y speed, z speed)"}, {"setName", lua_msn_ship_setName, "Changes ship name: (new name)"}, {"getTarget", lua_msn_ship_getTarget, "Returns handle to ship's targetted ship"}, {SCRIPT_END_LIST}, }; //LIBRARY define static const script_lua_obj_list lua_msn_lib_obj[] = { {l_ship.GetName(), lua_msn_ship_funcs, "Ship handle"}, {l_ship_info.GetName(), lua_msn_shipinfo_funcs, "Ship info handle"}, {SCRIPT_END_LIST}, }; static const script_lua_func_list lua_msn_lib[] = { {"newShip", lua_msn_newShip, "Creates a new ship and returns a handle to it: (ship name, class name, x pos, y pos, z pos; x rot, y rot, z rot)"}, {"getShipInfo", lua_msn_getShipInfo, "Gets ship info object"}, {SCRIPT_END_LIST}, }; //**********LIBRARY: Graphics (grl) //*****Class: model SCRIPT_LUA_CALLBACK lua_grpc_model_getFilename(lua_State *L) { polymodel *pm; if(!lua_parse_args(L, "o", l_model.Parse(&pm))) return 0; return lua_return_args(L, "s", pm->filename); } SCRIPT_LUA_CALLBACK lua_grpc_model_getnumEyepoints(lua_State *L) { polymodel *pm; if(!lua_parse_args(L, "o", l_model.Parse(&pm))) return 0; return lua_return_args(L, "s", pm->filename); } SCRIPT_LUA_CALLBACK lua_grpc_model_getEyepointPos(lua_State *L) { polymodel *pm; int idx; if(!lua_parse_args(L, "oi", l_model.Parse(&pm), &idx)) return 0; if(idx > -1 && idx < pm->n_view_positions) { return lua_return_args(L, "o", l_lvec.Return(&pm->view_positions[idx].pnt)); } return LUA_RETURN_NOTHING; } static const script_lua_obj_func_list lua_grpc_model_funcs[] = { {"getFilename", lua_grpc_model_getFilename, "Gets the model's filename", NULL,"string"}, {"getnumEyepoints", lua_grpc_model_getnumEyepoints, "Gets number of eyepoints on ship", NULL,"number"}, {"getEyepointPos", lua_grpc_model_getEyepointPos, "Gets selected eye position", "number","lvec"}, {SCRIPT_END_LIST}, }; //*****Functions: Graphics library SCRIPT_LUA_CALLBACK lua_grpc_loadModel(lua_State *L) { char *model_name; if(!lua_parse_args(L, "s", &model_name)) return 0; int idx = model_load(model_name, 0, NULL, 0); if(idx != -1) { polymodel *pm = model_get(idx); if(pm != NULL) { return lua_return_args(L, "o", l_model.Return(&pm)); } } return LUA_RETURN_NOTHING; } SCRIPT_LUA_CALLBACK lua_grpc_setColor(lua_State *L) { if(!Gr_inited) return 0; int r,g,b,a=255; if(!lua_parse_args(L, "iii|i", &r, &g, &b, &a)) return 0; color ac; gr_init_alphacolor(&ac,r,g,b,a); gr_set_color_fast(&ac); return 0; } SCRIPT_LUA_CALLBACK lua_grpc_setFont(lua_State *L) { if(!Gr_inited) return 0; int fn; if(!lua_parse_args(L, "i", &fn)) return 0; gr_set_font(fn); return 0; } SCRIPT_LUA_CALLBACK lua_grpc_drawPixel(lua_State *L) { if(!Gr_inited) return 0; int x,y; bool r=true; if(!lua_parse_args(L, "ii|b", &x, &y, &r)) return 0; gr_pixel(x,y,r); return 0; } SCRIPT_LUA_CALLBACK lua_grpc_drawLine(lua_State *L) { if(!Gr_inited) return 0; int x1,y1,x2,y2; bool r=true; if(!lua_parse_args(L, "iiii|b", &x1, &y1, &x2, &y2, &r)) return 0; gr_line(x1,y1,x2,y2,r); return 0; } SCRIPT_LUA_CALLBACK lua_grpc_drawGradientLine(lua_State *L) { if(!Gr_inited) return 0; int x1,y1,x2,y2; bool r=true; if(!lua_parse_args(L, "iiii|b", &x1, &y1, &x2, &y2, &r)) return 0; gr_gradient(x1,y1,x2,y2,r); return 0; } SCRIPT_LUA_CALLBACK lua_grpc_drawCircle(lua_State *L) { if(!Gr_inited) return 0; int x,y,ra; bool r=true; if(!lua_parse_args(L, "iii|b", &x,&y,&ra,&r)) return 0; gr_circle(x,y, ra, r); return 0; } SCRIPT_LUA_CALLBACK lua_grpc_drawCurve(lua_State *L) { if(!Gr_inited) return 0; int x,y,ra,d; if(!lua_parse_args(L, "iiii|b", &x,&y,&ra,&d)) return 0; gr_curve(x,y,ra,d); return 0; } SCRIPT_LUA_CALLBACK lua_grpc_drawText(lua_State *L) { if(!Gr_inited) return 0; int x,y; char *s; bool r=true; if(!lua_parse_args(L, "iis|b", &x, &y, &s, &r)) return 0; gr_string(x,y,s,r); return 0; } SCRIPT_LUA_CALLBACK lua_grpc_flashScreen(lua_State *L) { if(!Gr_inited) return 0; int r,g,b; if(!lua_parse_args(L, "iii", &r, &g, &b)) return 0; gr_flash(r,g,b); return 0; } //LIBRARY define static const script_lua_func_list lua_grpc_lib[] = { {"loadModel", lua_grpc_loadModel, "Loads the given model and returns a handle to it", "string","model"}, {"setColor", lua_grpc_setColor, "Sets the current drawing color: (red, green, blue; alpha)"}, {"setFont", lua_grpc_setFont, "Sets the current drawing font: (font number)"}, {"drawPixel", lua_grpc_drawPixel, "Draws a pixel using the current color: (x, y; resize)"}, {"drawLine", lua_grpc_drawLine, "Draws a line using the current color: (x1, y1, x2, y2; resize)"}, {"drawGradientLine", lua_grpc_drawGradientLine, "Draws a line using the current color that gradually fades out: (x1, y1, x2, y2; resize)"}, {"drawCircle", lua_grpc_drawCircle, "Draws a circle using the current color: (x,y,radius; resize)"}, {"drawCurve", lua_grpc_drawCurve, "Draws a curve using the current color: (x,y,radius,direction)"}, {"drawText", lua_grpc_drawText, "Draws text using the current font and color: (x, y, text; resize)"}, {"flashScreen", lua_grpc_flashScreen, "Flashes the screen with the specified color: (red,green,blue)"}, {SCRIPT_END_LIST}, }; static const script_lua_obj_list lua_grpc_lib_obj[] = { {l_model.GetName(), lua_grpc_model_funcs, "Model"}, {SCRIPT_END_LIST}, }; //**********LIBRARY Array //Add an item in here to add an item to scripting. //Elements: {library name, library function list, library object list} const script_lua_lib_list Lua_libraries[] = { {"grpc", lua_grpc_lib, lua_grpc_lib_obj, "Graphics library"}, {"misn", lua_msn_lib, lua_msn_lib_obj, "Mission library"}, {NULL, lua_base_lib, lua_base_lib_obj, "Base FS2 library"}, {SCRIPT_END_LIST}, }; */ #endif //USE_LUA //*************************Housekeeping************************* //Inits LUA //Note that "libraries" must end with a {NULL, NULL} //element int script_state::CreateLuaState() { #ifdef USE_LUA lua_State *L = lua_open(); /* opens Lua */ luaopen_base(L); /* opens the basic library */ luaopen_table(L); /* opens the table library */ //LUAJIT hates io :( luaopen_io(L); /* opens the I/O library */ luaopen_string(L); /* opens the string lib. */ luaopen_math(L); /* opens the math lib. */ if(L == NULL) { Warning(LOCATION, "Could not initialize Lua"); return 0; } //INITIALIZE ALL LIBRARY FUNCTIONS lua_lib_h *lib = &lua_Libraries[0]; lua_lib_h *lib_end = &lua_Libraries[lua_Libraries.size()]; lua_func_hh *func; lua_func_hh *func_end; for(lib = &lua_Libraries[0]; lib < lib_end; lib++) { //If a library name is given, register functions as library items //If not, register functions as globals if(lib->Name != NULL && strlen(lib->Name)) { //Register library functions //luaL_register(L, lib->library_name, lib->library_funcs); //luaL_openlib(L, lib->library_name, lib->library_funcs, 0); //NOTE FROM WMC: //The following is based on luaL_openlib from lauxlib.c //The default library can't be used because my custom script //function array features a field for function description //Check for the library's existence lua_pushstring(L, lib->Name); lua_gettable(L, LUA_GLOBALSINDEX); //If it doesn't exist... if (lua_isnil(L, -1)) { lua_pop(L, 1); //Pop the nil resultfrom the stack lua_newtable(L); //Create a new table lua_pushstring(L, lib->Name); //Add a string to the stack lua_pushvalue(L, -2); //Push the table lua_settable(L, LUA_GLOBALSINDEX); //Register the table with the new name } func = &lib->Functions[0]; func_end = &lib->Functions[lib->Functions.size()]; for(; func < func_end; func++) { //Add each function lua_pushstring(L, func->Name); //Push the function's name onto the stack lua_pushcclosure(L, func->Function, 0); //Push the function pointer onto the stack lua_settable(L, -3); //Add it into the current lib table } } else { //Iterate through the function list func = &lib->Functions[0]; func_end = &lib->Functions[lib->Functions.size()]; for(; func < func_end; func++) { //Sanity checking Assert(func->Name != NULL && strlen(func->Name)); Assert(func->Function != NULL); //Register the function with the name given as a global lua_register(L, func->Name, func->Function); } } //Handle objects and their methods in a library } lib = &lua_Objects[0]; lib_end = &lua_Objects[lua_Objects.size()]; for(; lib < lib_end; lib++) { if(!luaL_newmetatable(L, lib->Name)) { Warning(LOCATION, "Couldn't create metatable for object '%s'", lib->Name); continue; } //Get the absolute position of the object metatable for later use int table_loc = lua_gettop(L); //***Add the functions into the metatables //Because both the [] operator and function list share the "__index" //entry in the metatable, we must check for both and give an error //to be safe bool index_oper_already = false; bool index_meth_already = false; func = &lib->Functions[0]; func_end = &lib->Functions[lib->Functions.size()]; for(; func < func_end; func++) { if(!strnicmp(func->Name, "__", 2)) { if(!stricmp(func->Name, "__index")) { if(!index_meth_already){ index_oper_already = true; } else { Error(LOCATION, "Attempt to set both an indexing operator and methods for Lua class '%s'; get a coder", lib->Name); } } lua_pushstring(L, func->Name); lua_pushcclosure(L, func->Function, 0); lua_settable(L, table_loc); } else //This is an object method { if(index_oper_already) { Error(LOCATION, "Attempt to set both an indexing operator and methods for Lua class '%s'; get a coder", lib->Name); } if(!index_meth_already) { //Create the metatable lua_pushstring(L, "__index"); lua_pushvalue(L, table_loc); // pushes the metatable lua_settable(L, table_loc); // metatable.__index = metatable index_meth_already = true; } lua_pushstring(L, func->Name); lua_pushcclosure(L, func->Function, 0); lua_settable(L, -3); } } } SetLuaSession(L); return 1; #else return 0; #endif } #ifdef USE_LUA void output_lib_meta(FILE *fp, lua_lib_h *lib) { lua_func_hh *func = &lib->Functions[0]; lua_func_hh *func_end = &lib->Functions[lib->Functions.size()]; fputs("
", fp); for(; func < func_end; func++) { if(func->Arguments != NULL) { fprintf(fp, "
%s(%s)
", func->Name, func->Arguments); } else { fprintf(fp, "
%sNone
", func->Name); } if(func->Description != NULL) { fprintf(fp, "
%s
", func->Description); } else { fputs("
No description
", fp); } if(func->ReturnValues != NULL) { fprintf(fp, "
Return values: %s
", func->ReturnValues); } else { fputs("
Return values: None
", fp); } } fputs("
", fp); } #endif void script_state::OutputLuaMeta(FILE *fp) { #ifdef USE_LUA bool unnamed_display = false; //***Output Libraries fputs("
", fp); fputs("
Libraries
", fp); lua_lib_h *lib = &lua_Libraries[0]; lua_lib_h *lib_end = &lua_Libraries[lua_Libraries.size()]; for(; lib < lib_end; lib++) { fprintf(fp, "
%s - %s
", lib->Name, lib->Name, lib->Description); } //***Output objects lib = &lua_Objects[0]; lib_end = &lua_Objects[lua_Objects.size()]; fputs("
Objects
", fp); for(; lib < lib_end; lib++) { fprintf(fp, "
%s - %s
", lib->Name, lib->Name, lib->Description); } fputs("


", fp); //***Output libs fputs("
", fp); lib = &lua_Libraries[0]; lib_end = &lua_Libraries[lua_Libraries.size()]; for(; lib < lib_end; lib++) { fprintf(fp, "

%s - %s

", lib->Name, lib->Name, lib->Description); output_lib_meta(fp, lib); } //***Output objects lib = &lua_Objects[0]; lib_end = &lua_Objects[lua_Objects.size()]; for(; lib < lib_end; lib++) { fprintf(fp, "

%s - %s

", lib->Name, lib->Name, lib->Description); output_lib_meta(fp, lib); } fputs("
", fp); #endif }