#include "ai/ai.h" #include "ai/aigoals.h" #include "asteroid/asteroid.h" #include "camera/camera.h" #include "cfile/cfilesystem.h" #include "cmdline/cmdline.h" #include "cutscene/movie.h" #include "debris/debris.h" #include "freespace.h" #include "gamesequence/gamesequence.h" #include "globalincs/linklist.h" #include "graphics/2d.h" #include "graphics/font.h" #include "graphics/generic.h" #include "graphics/opengl/gropenglpostprocessing.h" #include "headtracking/headtracking.h" #include "hud/hudbrackets.h" #include "hud/hudconfig.h" #include "hud/hudescort.h" #include "hud/hudets.h" #include "hud/hudgauges.h" #include "hud/hudshield.h" #include "iff_defs/iff_defs.h" #include "io/joy.h" #include "io/key.h" #include "io/mouse.h" #include "io/timer.h" #include "jumpnode/jumpnode.h" #include "lighting/lighting.h" #include "menuui/credits.h" #include "mission/missioncampaign.h" #include "mission/missiongoals.h" #include "mission/missionload.h" #include "mission/missionlog.h" #include "mission/missionmessage.h" #include "mission/missiontraining.h" #include "missionui/missionbrief.h" #include "model/model.h" #include "network/multi.h" #include "network/multimsgs.h" #include "object/objectshield.h" #include "object/waypoint.h" #include "parse/parselo.h" #include "scripting/scripting.h" #include "particle/particle.h" #include "playerman/player.h" #include "render/3d.h" #include "render/3dinternal.h" #include "scripting/ade_api.h" #include "ship/ship.h" #include "ship/shipfx.h" #include "ship/shiphit.h" #include "sound/audiostr.h" #include "sound/ds.h" #include "weapon/beam.h" #include "weapon/weapon.h" #define BMPMAN_INTERNAL #include "bmpman/bm_internal.h" #include "scripting/api/bitops.h" #include "scripting/api/enums.h" #include "scripting/api/vecmath.h" #include "scripting/api/event.h" #include "scripting/api/file.h" #include "scripting/api/font.h" #include "scripting/api/gameevent.h" #include "scripting/api/gamestate.h" #include "scripting/api/hudgauge.h" #include "scripting/api/eye.h" #include "scripting/api/model.h" #include "scripting/api/physics_info.h" #include "scripting/api/sexpvar.h" #include "scripting/api/shields.h" #include "scripting/api/shiptype.h" #include "scripting/api/species.h" #include "scripting/api/team.h" #include "scripting/api/streaminganim.h" #include "scripting/api/texture.h" #include "scripting/api/texturemap.h" #include "scripting/api/weaponclass.h" #include "scripting/api/mc_info.h" #include "scripting/api/object.h" #include "scripting/api/asteroid.h" #include "scripting/api/cockpit_display.h" #include "scripting/api/shipclass.h" #include "scripting/api/debris.h" #include "scripting/api/waypoint.h" #include "scripting/api/ship_bank.h" #include "scripting/api/subsystem.h" #include "scripting/api/order.h" #include "scripting/api/ship.h" #include "scripting/api/sound.h" #include "scripting/api/message.h" #include "scripting/api/wing.h" #include "scripting/api/beam.h" #include "scripting/api/player.h" #include "scripting/api/camera.h" #include "scripting/api/control_info.h" #include "scripting/api/particle.h" #include "scripting/api/audio.h" #include "scripting/api/base.h" #include "scripting/api/cfile.h" #include "scripting/api/weapon.h" #include "scripting/api/controls.h" #include "scripting/api/graphics.h" #include "scripting/api/hud.h" #include "scripting/api/hookvars.h" #include "scripting/api/mission.h" #include "scripting/api/tables.h" using namespace scripting; using namespace scripting::api; //**********Handles /*ade_obj l_Camera("camera", "Camera handle"); ade_obj l_Cmission("cmission", "Campaign mission handle"); //WMC - We can get away with a pointer right now, but if it ever goes dynamic, it'd be a prob ade_obj l_Enum("enumeration", "Enumeration object"); ade_obj l_Event("event", "Mission event handle"); ade_obj l_Font("font", "font handle"); ade_obj l_Matrix("orientation", "Orientation matrix object"); ade_obj l_Model("model", "3D Model (POF) handle"); ade_obj l_Object("object", "Object handle"); ade_obj l_Physics("physics", "Physics handle"); ade_obj l_Player("player", "Player handle"); ade_obj l_Shields("shields", "Shields handle"); ade_obj l_Ship("ship", "Ship handle", &l_Object); ade_obj l_Shipclass("shipclass", "Ship class handle"); ade_obj l_ShipTextures("shiptextures", "Ship textures handle"); ade_obj l_Shiptype("shiptype", "Ship type handle"); ade_obj l_Species("species", "Species handle"); ade_obj l_Subsystem("subsystem", "Ship subsystem handle"); ade_obj l_Team("team", "Team handle"); ade_obj l_Texture("texture", "Texture handle"); ade_obj l_Wing("wing", "Wing handle"); ade_obj l_Vector("vector", "Vector object"); ade_obj l_Weapon("weapon", "Weapon handle", &l_Object); ade_obj l_WeaponBank("weaponbank", "Ship/subystem weapons bank handle"); ade_obj l_WeaponBankType("weaponbanktype", "Ship/subsystem weapons bank type handle"); ade_obj l_Weaponclass("weaponclass", "Weapon class handle"); */ //########################################################### //################################################ //########################################################### //If you are a coder who wants to add libraries, functions, //or objects to Lua, then you want to be below this point. //########################################################### //############################################### //########################################################### //*************************Testing stuff************************* //This section is for stuff that's considered experimental. ade_lib l_Testing("Testing", NULL, "ts", "Experimental or testing stuff"); ADE_FUNC(avdTest, l_Testing, NULL, "Test the AVD Physics code", NULL, NULL) { static bool initialized = false; static avd_movement avd; if(!initialized) { avd.setAVD(10.0f, 3.0f, 1.0f, 1.0f, 0.0f); initialized = true; } for(int i = 0; i < 3000; i++) { float Pc, Vc; avd.get((float)i/1000.0f, &Pc, &Vc); gr_set_color(0, 255, 0); gr_pixel(i/10, gr_screen.clip_bottom - (int)(Pc*10.0f), GR_RESIZE_NONE); gr_set_color(255, 0, 0); gr_pixel(i/10, gr_screen.clip_bottom - (int)(Vc*10.0f), GR_RESIZE_NONE); avd.get(&Pc, &Vc); gr_set_color(255, 255, 255); gr_pixel((timestamp()%3000)/10, gr_screen.clip_bottom - (int)(Pc*10.0f), GR_RESIZE_NONE); gr_pixel((timestamp()%3000)/10, gr_screen.clip_bottom - (int)(Vc*10.0f), GR_RESIZE_NONE); } return ADE_RETURN_NIL; } ADE_FUNC(createParticle, l_Testing, "vector Position, vector Velocity, number Lifetime, number Radius, enumeration Type, [number Tracer length=-1, boolean Reverse=false, texture Texture=Nil, object Attached Object=Nil]", "Creates a particle. Use PARTICLE_* enumerations for type." "Reverse reverse animation, if one is specified" "Attached object specifies object that Position will be (and always be) relative to.", "particle", "Handle to the created particle") { particle::particle_info pi; pi.type = particle::PARTICLE_DEBUG; pi.optional_data = -1; pi.attached_objnum = -1; pi.attached_sig = -1; pi.reverse = 0; // Need to consume tracer_length parameter but it isn't used anymore float temp; enum_h *type = NULL; bool rev=false; object_h *objh=NULL; if(!ade_get_args(L, "ooffo|fboo", l_Vector.Get(&pi.pos), l_Vector.Get(&pi.vel), &pi.lifetime, &pi.rad, l_Enum.GetPtr(&type), &temp, &rev, l_Texture.Get((int*)&pi.optional_data), l_Object.GetPtr(&objh))) return ADE_RETURN_NIL; if(type != NULL) { switch(type->index) { case LE_PARTICLE_DEBUG: pi.type = particle::PARTICLE_DEBUG; break; case LE_PARTICLE_FIRE: pi.type = particle::PARTICLE_FIRE; break; case LE_PARTICLE_SMOKE: pi.type = particle::PARTICLE_SMOKE; break; case LE_PARTICLE_SMOKE2: pi.type = particle::PARTICLE_SMOKE2; break; case LE_PARTICLE_BITMAP: if (pi.optional_data < 0) { LuaError(L, "Invalid texture specified for createParticle()!"); } pi.type = particle::PARTICLE_BITMAP; break; } } if(rev) pi.reverse = 0; if(objh != NULL && objh->IsValid()) { pi.attached_objnum = OBJ_INDEX(objh->objp); pi.attached_sig = objh->objp->signature; } particle::WeakParticlePtr p = particle::create(&pi); if (!p.expired()) return ade_set_args(L, "o", l_Particle.Set(particle_h(p))); else return ADE_RETURN_NIL; } ADE_FUNC(getStack, l_Testing, NULL, "Generates an ADE stackdump", "string", "Current Lua stack") { char buf[10240] = {'\0'}; ade_stackdump(L, buf); return ade_set_args(L, "s", buf); } ADE_FUNC(isCurrentPlayerMulti, l_Testing, NULL, "Returns whether current player is a multiplayer pilot or not.", "boolean", "Whether current player is a multiplayer pilot or not") { if(Player == NULL) return ade_set_error(L, "b", false); if(!(Player->flags & PLAYER_FLAGS_IS_MULTI)) return ADE_RETURN_FALSE; return ADE_RETURN_TRUE; } // Om_tracker_flag should already be set in FreeSpace.cpp, needed to determine if PXO is enabled from the registry extern int Om_tracker_flag; // needed for FS2OpenPXO config ADE_FUNC(isPXOEnabled, l_Testing, NULL, "Returns whether PXO is currently enabled in the configuration.", "boolean", "Whether PXO is enabled or not") { if(!(Om_tracker_flag)) return ADE_RETURN_FALSE; return ADE_RETURN_TRUE; } ADE_FUNC(playCutscene, l_Testing, NULL, "Forces a cutscene by the specified filename string to play. Should really only be used in a non-gameplay state (i.e. start of GS_STATE_BRIEFING) otherwise odd side effects may occur. Highly Experimental.", "string", NULL) { //This whole thing is a quick hack and can probably be done way better, but is currently functioning fine for my purposes. char *filename; if (!ade_get_args(L, "s", &filename)) return ADE_RETURN_FALSE; movie::play(filename); return ADE_RETURN_TRUE; } //########################################################### //################################################ //########################################################### //If you are a coder who wants to add libraries, functions, //or objects to Lua, then you want to be above this point. //########################################################### //############################################### //########################################################### // *************************Housekeeping************************* //WMC - The miraculous lines of code that make Lua debugging worth something. lua_Debug Ade_debug_info; char debug_stack[4][32]; void ade_debug_ret(lua_State *L, lua_Debug *ar) { Assert(L != NULL); Assert(ar != NULL); lua_getstack(L, 1, ar); lua_getinfo(L, "nSlu", ar); memcpy(&Ade_debug_info, ar, sizeof(lua_Debug)); int n; for (n = 0; n < 4; n++) { debug_stack[n][0] = '\0'; } for (n = 0; n < 4; n++) { if (lua_getstack(L,n+1, ar) == 0) break; lua_getinfo(L,"n", ar); if (ar->name == NULL) break; strcpy_s(debug_stack[n],ar->name); } } //WMC - because the behavior of the return keyword //was changed, I now have to use this in hooks. static int ade_return_hack(lua_State *L) { int i = 0; int num = lua_gettop(L); for(i = 0; i < num; i++) { lua_pushvalue(L, i+1); } return num; } static void *vm_lua_alloc(void*, void *ptr, size_t, size_t nsize) { if (nsize == 0) { vm_free(ptr); return NULL; } else { return vm_realloc(ptr, nsize); } } //Inits LUA //Note that "libraries" must end with a {NULL, NULL} //element int script_state::CreateLuaState() { mprintf(("LUA: Opening LUA state...\n")); lua_State *L = lua_newstate(vm_lua_alloc, nullptr); if(L == NULL) { Warning(LOCATION, "Could not initialize Lua"); return 0; } //*****INITIALIZE AUXILIARY LIBRARIES mprintf(("LUA: Initializing base Lua libraries...\n")); luaL_openlibs(L); //*****DISABLE DANGEROUS COMMANDS lua_pushstring(L, "os"); lua_rawget(L, LUA_GLOBALSINDEX); int os_ldx = lua_gettop(L); if(lua_istable(L, os_ldx)) { lua_pushstring(L, "execute"); lua_pushnil(L); lua_rawset(L, os_ldx); lua_pushstring(L, "remove"); lua_pushnil(L); lua_rawset(L, os_ldx); lua_pushstring(L, "rename"); lua_pushnil(L); lua_rawset(L, os_ldx); } lua_pop(L, 1); //os table //*****SET DEBUG HOOKS #ifndef NDEBUG lua_sethook(L, ade_debug_ret, LUA_MASKRET, 0); #endif //*****INITIALIZE ADE uint i; mprintf(("LUA: Beginning ADE initialization\n")); for(i = 0; i < ade_manager::getInstance()->getNumEntries(); i++) { //WMC - Do only toplevel table entries, doi if(ade_manager::getInstance()->getEntry(i).ParentIdx == UINT_MAX) //WMC - oh hey, we're done with the meaty point in < 10 lines. ade_manager::getInstance()->getEntry(i).SetTable(L, LUA_GLOBALSINDEX, LUA_GLOBALSINDEX); //Oh the miracles of OOP. } //*****INITIALIZE RETURN HACK FUNCTION lua_pushstring(L, "ade_return_hack"); lua_pushboolean(L, 0); lua_pushcclosure(L, ade_return_hack, 2); lua_setglobal(L, "ade_return_hack"); //*****INITIALIZE ENUMERATION CONSTANTS mprintf(("ADE: Initializing enumeration constants...\n")); enum_h eh; for(i = 0; i < Num_enumerations; i++) { eh.index = Enumerations[i].def; eh.is_constant = true; ade_set_args(L, "o", l_Enum.Set(eh)); lua_setglobal(L, Enumerations[i].name); } //*****ASSIGN LUA SESSION mprintf(("ADE: Assigning Lua session...\n")); SetLuaSession(L); // (void)l_BitOps.GetName(); return 1; } void script_state::EndLuaFrame() { scripting::api::graphics_on_frame(); } void ade_output_toc(FILE *fp, ade_table_entry *ate) { Assert(fp != NULL); Assert(ate != NULL); //WMC - sanity checking if(ate->Name == NULL && ate->ShortName == NULL) { Warning(LOCATION, "Found ade_table_entry with no name or shortname"); return; } fputs("
", fp); if(ate->Name == NULL) { fprintf(fp, "%s", ate->ShortName, ate->ShortName); } else { fprintf(fp, "%s", ate->Name, ate->Name); if(ate->ShortName) fprintf(fp, " (%s)", ate->ShortName); } fputs("", fp); if(ate->Description) fprintf(fp, " - %s\n", ate->Description); fputs("
\n", fp); } static bool sort_table_entries(const ade_table_entry* left, const ade_table_entry* right) { const char* leftCmp = left->Name != nullptr ? left->Name : left->ShortName; const char* rightCmp = right->Name != nullptr ? right->Name : left->ShortName; if (leftCmp == nullptr) { return false; } if (rightCmp == nullptr) { return false; } SCP_string leftStr(leftCmp); std::transform(std::begin(leftStr), std::end(leftStr), std::begin(leftStr), ::tolower); SCP_string rightStr(rightCmp); std::transform(std::begin(rightStr), std::end(rightStr), std::begin(rightStr), ::tolower); return leftStr < rightStr; } static bool sort_doc_entries(const ade_table_entry* left, const ade_table_entry* right) { if (left->Instanced == right->Instanced) { // Same type -> compare as normal return sort_table_entries(left, right); } if (left->Instanced) { return true; } return false; } void script_state::OutputLuaMeta(FILE *fp) { uint i; ade_table_entry *ate; fputs("
\n", fp); SCP_vector table_entries; //***TOC: Libraries fputs("
Libraries
\n", fp); for(i = 0; i < ade_manager::getInstance()->getNumEntries(); i++) { ate = &ade_manager::getInstance()->getEntry(i); if(ate->ParentIdx == UINT_MAX && ate->Type == 'o' && ate->Instanced) { table_entries.push_back(ate); } } std::sort(std::begin(table_entries), std::end(table_entries), sort_table_entries); for (auto entry : table_entries) { ade_output_toc(fp, entry); } table_entries.clear(); //***TOC: Objects fputs("
Types
\n", fp); for(i = 0; i < ade_manager::getInstance()->getNumEntries(); i++) { ate = &ade_manager::getInstance()->getEntry(i); if(ate->ParentIdx == UINT_MAX && ate->Type == 'o' && !ate->Instanced) { table_entries.push_back(ate); } } std::sort(std::begin(table_entries), std::end(table_entries), sort_table_entries); for (auto entry : table_entries) { ade_output_toc(fp, entry); } table_entries.clear(); //***TOC: Enumerations fputs("
Enumerations
", fp); //***End TOC fputs("


", fp); //***Everything fputs("
\n", fp); for(i = 0; i < ade_manager::getInstance()->getNumEntries(); i++) { ate = &ade_manager::getInstance()->getEntry(i); if(ate->ParentIdx == UINT_MAX) table_entries.push_back(ate); } std::sort(std::begin(table_entries), std::end(table_entries), sort_doc_entries); for (auto entry : table_entries) { entry->OutputMeta(fp); } table_entries.clear(); //***Enumerations fprintf(fp, "

Enumerations

"); for(i = 0; i < Num_enumerations; i++) { //WMC - This is in case we ever want to add descriptions to enums. //fprintf(fp, "
%s
%s
", Enumerations[i].name, Enumerations[i].desc); //WMC - Otherwise, just use this. fprintf(fp, "
%s
", Enumerations[i].name); } fputs("
\n", fp); //***End LUA fputs("\n", fp); }