Jump to content

Mjjstral

Members
  • Content count

    109
  • Joined

  • Last visited

Community Reputation

23 Very Good

About Mjjstral

  • Rank
    Specialist

Contact Methods

Profile Information

  • Location
    Germany
  • Interests
    philosophy, border science, science fiction

Command & Conquer Profile

  • Favourite C&C
    Kanes Wrath

Recent Profile Visitors

1,962 profile views
  1. http://lua-users.org/wiki/PersistentTables Usage as mentioned in the examples: make_persistent(globals(),"C:/Anywhere/") Also here is a prototype I made myself quickly that creates one lua savefile. You can then recreate the savestate with dofile(savefile). function SaveLuaState(savepath) local Save = "" for index,value in globals() do if type(value) == "number" then Save = Save .. index .. " = " .. value .."\n" elseif type(value) == "string" then if strfind(value,"\\") or strfind(value,"\n") then Save = Save .. index .. " = " .. strrep(strchar(91),2) .. value .. strrep(strchar(93),2) .. "\n" else Save = Save .. index .. " = " .. "'" .. value .. "'" .. "\n" end elseif type(value) == "table" and not strfind(index,"ObjID") then Save = Save .. index .. " = {" for t_index,t_value in value do if type(t_value) == "number" then if type(t_index) == "number" then Save = Save .. "\t[" .. t_index .. "]=" .. t_value .. "," elseif type(t_index) == "string" then Save = Save .. "\t['" .. t_index .. "']=" .. t_value .. "," end elseif type(t_value) == "string" then if type(t_index) == "number" then Save = Save .. "\t[" .. t_index .. "]='" .. t_value .. "'," elseif type(t_index) == "string" then Save = Save .. "\t['" .. t_index .. "']='" .. t_value .. "'," end else --Save = Save .. "\n\t['" .. t_index .. "']=" .. t_value .. "," end end Save = Save .. "}\n" end end local filehandle = openfile(savepath, 'w') if filehandle ~= nil then write(filehandle, Save) flush(filehandle) closefile(filehandle) end end Next step is a lua savefile to game savefile identifier function that then loads the lua save. It could simply be executed in the ususal scipts.lua environment. If your patient I will provide all that with the "Meta" dll framework. It hooks the save function and cares for everything automatically so modders doesn't have to care anymore about lost lua vars in saves.
  2. Nice ! Will probably put it on github at some point Yes see this question. In the long run extending the actual savegame routine would be the way to go I admit. As I have written this is how it will work in sage meta tool (unreleased yet). The game is not able to handle coord3d parameters from lua in any way so I had to write a new parameter parser for it. Until then use the old method but keep in mind it depends on objects and ocls (not pure lua).
  3. You first need to initialize the global counters by using InitializeGCounters(). This will setup 10 counters with values 1 to 10. SetCounter will then do math with these global counters to get your desired counter value. This is because the regular counter commands for some reason don't work. So this is a workaround that works great. This is a compilcated monster that fortunately gets replaced in the sage meta tool project with a muuuch faster and more convenient solution. This old method works like that in short: Spawns ocl dummy anchors with positional offsets (defined in ocl) on itself again and again until the desired position is reached. Then it uses "CREATE_NAMED_ON_TEAM_AT_OBJECTTYPE" to spawn the actual object on the invisible anchor. It also uses a self made lua stack system to process multiple spawn requests because that whole method gets not executed between two frames. The new method will work like that with a COORD3D lua table {x,y,z}: ExecuteAction("UNIT_SPAWN_NAMED_LOCATION_ORIENTATION", ObjectName, ObjectType, Team, {PositionX, PositionY, PositionZ}, Orientation) Yes completely new UI and a parser to show infos about these gamemodes + update functionality (pastebin dl based).
  4. Hi pengion, sorry for the late reply ! So I'm not sure how exactly you make the tower defense map and if you use the in the meta mod sdk pdf described procedure to make special meta mod tower defense maps or some variant of your own so I have to give you a general answer: First you set your function that gets executed every second and checks for the timer (assuming you have only one timer set). TIME_THRESHOLD = 120 function Coroutine() for counter,time in TimerTable do if time <= TIME_THRESHOLD then --your action here end end end Next step is to give it to the script timer so that this function above gets executed every second: SetScriptTimer(1,Coroutine,-1) The last argument is the number of executions. -1 means execute infinitely. The first argument is the time intervall between each execution. Note you can also create custom gamemode luas as descibed in the meta mod manual. Btw I'm working on a new successor project that will come as a dll mod and will in particular support new custom gamemodes by a new skirmish setup submenu (news on the sage modding discord).
  5. To answer your question, yes you can make custom savegames with lua file io commands. If you use a timestamp you can load exactly the state you need. I made custom savegames in many variations in metamod (base templates, auto start config, stats save) . The source code is completely open so have a look and report how that works out. The main function you will have to work with is WriteToFile and LoadFile (from meta mod).
  6. I've build a spawner system in meta mod with lua. You can incorporate it into your mod. For an example see the meta menu spawner submenu that has a random position option to spawn any object. Initial load mechanism is as follows: playertemplate invisible start object dummy OR spellbook -> OnCreate lua event -> lua random spawn function
  7. You need to know one thing: You can theoretically disable the AI and completely rebuild it in lua. That means you can also mimic only parts of it like the desire you mentioned above. https://pastebin.com/xHHGCVZ1
  8. Mjjstral

    Kanes Wrath InGameUISettings Schemas

    Hey really nice to see that file to be useable now. Do you or someone else know if we can change the text offset of "military captions" with that file. I need that for my metamod to hide the "missing:..." string in the meta command menu. Moving the text up so that it moves out of the visible screen would be great.
  9. Clear the Compilation folder (WrathEDSDK_Folder/Compilation/Mods/YourMod). If it is path related, move the SDK folder to the root of C drive and try again. Maybe also delete the userdata WrathED creates (Documents\WrathEd).
  10. This should fix it. It's now more error robust in general: IronCurtain = {} IronCurtain["Targets"] = {} IronCurtain["BuildingRef"] = {} IronCurtain["Ready"] = {} function OnIronCurtainBuildingCreated(self) IronCurtain["BuildingRef"][ObjectTeamName(self)] = self if IronCurtain["Targets"][ObjectTeamName(self)] == nil then IronCurtain["Targets"][ObjectTeamName(self)] = {} end IronCurtain["Ready"][ObjectTeamName(self)] = false end function OnIronCurtainBuildingDestroyed(self) IronCurtain["BuildingRef"][ObjectTeamName(self)] = nil IronCurtain["Ready"][ObjectTeamName(self)] = false end function OnIronCurtainReady(self) IronCurtain["Ready"][ObjectTeamName(self)] = true if IronCurtain["Targets"][ObjectTeamName(self)] == nil then IronCurtain["Targets"][ObjectTeamName(self)] = {} end if IronCurtain["Targets"][ObjectTeamName(self)] and getn(IronCurtain["Targets"][ObjectTeamName(self)]) > 0 and not ObjectTestModelCondition(self,"UNDERPOWERED") then --ObjectCreateAndFireTempWeapon(IronCurtain["Targets"][1],"IronCurtainWeapon") ExecuteAction("NAMED_FIRE_SPECIAL_POWER_AT_NAMED",GetObj.String(self),"SpecialPower_IronCurtain",GetObj.String(IronCurtain["Targets"][ObjectTeamName(self)][1])) IronCurtain["Ready"][ObjectTeamName(self)] = false end end function OnHarvesterHealth25Percent(self) if IronCurtain["Targets"][ObjectTeamName(self)] == nil then IronCurtain["Targets"][ObjectTeamName(self)] = {} end tinsert(IronCurtain["Targets"][ObjectTeamName(self)],self) if IronCurtain["BuildingRef"][ObjectTeamName(self)] and IronCurtain["Ready"][ObjectTeamName(self)] and not ObjectTestModelCondition(IronCurtain["BuildingRef"][ObjectTeamName(self)],"UNDERPOWERED") then --ObjectCreateAndFireTempWeapon(self,"IronCurtainWeapon") ExecuteAction("NAMED_FIRE_SPECIAL_POWER_AT_NAMED",GetObj.String(IronCurtain["BuildingRef"][ObjectTeamName(self)]),"SpecialPower_IronCurtain",GetObj.String(self)) IronCurtain["Ready"][ObjectTeamName(self)] = false end end function OnHarvesterHealth25PercentNOT_OR_OnHarvesterDead(self) local Index = GetIndexOfTableElement(IronCurtain["Targets"][ObjectTeamName(self)],self) if Index then tremove(IronCurtain["Targets"][ObjectTeamName(self)], Index) end end function GetIndexOfTableElement(table,element) if not table then return nil end for i=1,getn(table),1 do if table[i]==element then return i end end end Hm I'm also on win7... Shouldn't be system dependent acually. Why does the lua code pasted in these forum text boxes appear so whitish and unreadable ?
  11. I'm currently trying to create a prototype of a logic circuits mod for Kane's Wrath. You will basically have different elements you can connect via cables. One Example: A "switch" and an "enemy detector" connected via an AND gate and the output cable leads to an "sound alarm" element. Functionally it will look like in games like Minecraft (redstone logic) or Starmade, see here: Now my problem: I need to connect the elements somehow via cables creating a hook up, latch or click in effect that somehow (likewise via modelcondition) triggers a lua event. I will handle the whole logic in lua then. Let's brainstorm ! Also what parts do you think should be added ? (so far on my list: lua computer terminal (like in ComputerCraft, each computer with own lua file), Gates, Structure Status Detector, AND, OR, NOT, switch, toggle switch, sound alarm, structure enabler/disabler, structure command giver (build commands...), unit command giver, laser trigger, team command giver, unit counter, seller, repairer, light (with rgb code connectors), text displayer) If someone wants to help me especially with the model creation and also xml coding wise (beside this forum), feel free to contact me (also consider joining the SAGE modding discord).
  12. And here is an alternative I made earlier but you can disregard. It uses lua script timers (meta mod) and gets the harvester refs automatically. So it's a more lua self contained solution. IronCurtainBuildingList = {} function IronCurtainBuildingOnCreated(self) tinsert(IronCurtainBuildingList,self) SetScriptTimer(1,IronCurtainAttackManagement) end function IronCurtainBuildingOnDestroyed(self) local Index = GetIndexOfTableElement(IronCurtainBuildingList,self) if Index then tremove(IronCurtainBuildingList, Index) end DeleteScriptTimerAction(IronCurtainAttackManagement) end function IronCurtainBuildingOnPowerOutage(self) local Index = GetIndexOfTableElement(IronCurtainBuildingList,self) if Index then tremove(IronCurtainBuildingList, Index) end DeleteScriptTimerAction(IronCurtainAttackManagement) end function IronCurtainBuildingOnPowerRestore(self) tinsert(IronCurtainBuildingList,self) SetScriptTimer(1,IronCurtainAttackManagement) end IronCurtainSchedule = {} function IronCurtainAttackManagement() local IronCurtainObjectWhiteList = GetObjectTypeListForTeam(team,AddToObjectTypeList("HarvesterTypeList","GDIHarvester","NODHarvester","ALIENHarvester")) for i=1,getn(IronCurtainBuildingList),1 do if IronCurtainSchedule[IronCurtainBuildingList[i]] == 0 and not ObjectTestModelCondition(GetObj.Table(IronCurtainBuildingList[i]),"UNDERPOWERED") then for j=1,getn(IronCurtainObjectWhiteList),1 do if GetHealth(IronCurtainObjectWhiteList[j].ref) <= 25 then ObjectCreateAndFireTempWeapon(IronCurtainObjectWhiteList[j].ref,"IronCurtainWeapon") --ExecuteAction("NAMED_USE_COMMANDBUTTON_ABILITY_ON_NAMED", IronCurtainBuildingList[i], "Command_IronCurtainWeapon", IronCurtainObjectWhiteList[j].ref) end end else IronCurtainSchedule[IronCurtainBuildingList[i]] = IronCurtainSchedule[IronCurtainBuildingList[i]] - 1 end end end function GetObjectTypeListForTeam(team,ObjectType) --ObjectType or ObjectTypeList local RefList = {} local ObjRef = "" local y = 1 local TempObjectRefTable={} ExecuteAction("SET_IGNORE_SKIRMISH_VICTORY_CONDITIONS", 1) repeat ObjRef=RandomString(5) ExecuteAction("TEAM_SET_PLAYERS_NEAREST_UNIT_OF_TYPE_TO_REFERENCE",ObjectType,team,ObjRef) if EvaluateCondition("NAMED_NOT_DESTROYED",ObjRef) then RefList[y]={} RefList[y]["ref"]=ObjRef RefList[y]["team"]=team RefList[y]["type"]=ObjectType RefList[y]["powered"]=1 tinsert(TempObjectRefTable,ObjRef) ExecuteAction("UNIT_SET_TEAM",ObjRef,"team") y=y+1 else break end until(not EvaluateCondition("NAMED_NOT_DESTROYED",ObjRef)) for j=1,getn(TempObjectRefTable),1 do ExecuteAction("UNIT_SET_TEAM",TempObjectRefTable[j],team) end ExecuteAction("SET_IGNORE_SKIRMISH_VICTORY_CONDITIONS", 0) return RefList end function AddToObjectTypeList(ObjectTypeList,...) for i=1,getn(arg),1 do ExecuteAction("OBJECTLIST_ADDOBJECTTYPE", ObjectTypeList, arg[i]) end return ObjectTypeList end function GetHealth(input,HealthType) local HealthCompareType = "" if HealthType == nil or HealthType == "unit" or HealthType == 1 then HealthCompareType = "UNIT_HEALTH" else HealthCompareType = "EVAL_TEAM_HEALTH" end for i=1,101,1 do if EvaluateCondition(HealthCompareType, input, CompareTable["<"], i) then return i-1 end end return 0 end function GetIndexOfTableElement(table,element) for i=1,getn(table),1 do if table[i]==element then return i end end end function GetObj.Table(object) if type(object) == "table" then return object else for k,v in globals() do if strfind(k,"ObjID") ~= nil and strfind(ObjectDescription(v),object) then return rawget(globals(),k) --v end end return object end end
  13. My solution assumes that a player will only have 1 iron curtain building at the same time (code adaption for more than 1 possible). 1. Make it a special power that triggers a weapon and then an attribute modifier. Use Ravendarks idea to trigger a SPECIALPOWER1_READY lua event that calls the function OnIronCurtainReady. 2. In additon for the harvesters use these events to trigger the functions OnHarvesterHealth25Percent and OnHarvesterHealth25PercentNOT_OR_OnHarvesterDead. <ModelConditionEvent Name="HEALTH_PERCENT_25"> <Conditions>+HEALTH_PERCENT_25</Conditions> </ModelConditionEvent> <ModelConditionEvent Name="HEALTH_PERCENT_25_NOT"> <Conditions>-HEALTH_PERCENT_25</Conditions> </ModelConditionEvent> 3. Now the lua code: IronCurtain = {} IronCurtain["Targets"] = {} IronCurtain["BuildingRef"] = {} IronCurtain["Ready"] = {} function OnIronCurtainBuildingCreated(self) IronCurtain["BuildingRef"][ObjectTeamName(self)] = self IronCurtain["Targets"][ObjectTeamName(self)] = {} IronCurtain["Ready"][ObjectTeamName(self)] = false end function OnIronCurtainBuildingDestroyed(self) IronCurtain["BuildingRef"][ObjectTeamName(self)] = nil IronCurtain["Ready"][ObjectTeamName(self)] = false end function OnIronCurtainReady(self) IronCurtain["Ready"][ObjectTeamName(self)] = true if getn(IronCurtain["Targets"][ObjectTeamName(self)]) > 0 and ObjectTestModelCondition(IronCurtain["BuildingRef"][ObjectTeamName(self)],"UNDERPOWERED") then --ObjectCreateAndFireTempWeapon(IronCurtain["Targets"][1],"IronCurtainWeapon") ExecuteAction("NAMED_FIRE_SPECIAL_POWER_AT_NAMED",GetObj.String(self),"SpecialPower_IronCurtain",GetObj.String(IronCurtain["Targets"][ObjectTeamName(self)][1])) IronCurtain["Ready"][ObjectTeamName(self)] = false end end function OnHarvesterHealth25Percent(self) tinsert(IronCurtain["Targets"][ObjectTeamName(self)],self) if IronCurtain["BuildingRef"][ObjectTeamName(self)] and IronCurtain["Ready"][ObjectTeamName(self)] and not ObjectTestModelCondition(IronCurtain["BuildingRef"][ObjectTeamName(self)],"UNDERPOWERED") then --ObjectCreateAndFireTempWeapon(self,"IronCurtainWeapon") ExecuteAction("NAMED_FIRE_SPECIAL_POWER_AT_NAMED",GetObj.String(IronCurtain["BuildingRef"][ObjectTeamName(self)]),"SpecialPower_IronCurtain",GetObj.String(self)) IronCurtain["Ready"][ObjectTeamName(self)] = false end end function OnHarvesterHealth25PercentNOT_OR_OnHarvesterDead(self) local Index = GetIndexOfTableElement(IronCurtain["Targets"][ObjectTeamName(self)],self) if Index then tremove(IronCurtain["Targets"][ObjectTeamName(self)], Index) end end function GetIndexOfTableElement(table,element) for i=1,getn(table),1 do if table[i]==element then return i end end end So you need in total 5 lua events (3 for the structure and 2 for the harvesters). 4. optionaly if you want to always attack the harbester with the lowest health from the pool of all harvesters that have health < 25: function GetMinHealthUnit(UnitTable) if getn(UnitTable) == 0 then return nil end local MinHealthUnitRef = UnitTable[1] local MinHealth = GetHealth(UnitTable[1]) for i=2,getn(UnitTable),1 do if GetHealth(UnitTable[i]) < MinHealth then MinHealthUnitRef = UnitTable[i] end end return MinHealthUnitRef end function GetHealth(Unit) local UnitRef = GetObj.String(Unit) for i=1,101,1 do if EvaluateCondition("UNIT_HEALTH", UnitRef, CompareTable["<"], i) then return i-1 end end return 0 end So replace GetObj.String(IronCurtain["Targets"][ObjectTeamName(self)][1]) with GetObj.String(GetMinHealthUnit(IronCurtain["Targets"][ObjectTeamName(self)]))
  14. I found the error: "NAMED_EXIT_ALL" gives a command to the transporter to thorw out it's inmates. So becomes much more simple: function OnSovietHalfTrackReallyDamaged(self) --add the lua event to scriptevents.xml too ExecuteAction("NAMED_EXIT_ALL",self) if PassengerTable[tostring(self)] == nil then return end for i=1,getn(PassengerTable[tostring(self)]),1 do ExecuteAction("UNIT_AI_TRANSFER",PassengerTable[tostring(self)][i],1) --enable ai in case it was disabled end PassengerTable[tostring(self)]=nil end If you want to give the exit commands to the inmates one by one you can use this: function OnSovietHalfTrackReallyDamaged(self) --add the lua event to scriptevents.xml too if PassengerTable[tostring(self)] == nil then return end for i=1,getn(PassengerTable[tostring(self)]),1 do ExecuteAction("NAMED_EXIT_BUILDING",PassengerTable[tostring(self)][i]) ExecuteAction("UNIT_AI_TRANSFER",PassengerTable[tostring(self)][i],1) --enable ai in case it was disabled end PassengerTable[tostring(self)]=nil end So to sum up: "NAMED_EXIT_ALL" = command for object harboring units, "NAMED_EXIT_BUILDING" = command for units within transporters (or buildings).
  15. I totally love procedural algortihms and after genuine games like No Man's Sky (proc planets, proc animals, proc plants, proc missions, proc ships, proc all xD) I was always thinking about how to use proc gen in the sage engine. Here is one idea I came up with: Procedural lua mission+story gamemode, playable on any map (map independent): 1. Mission Templates: These are the puzzle pieces that get merged together to create a mission. I expect 20-30 unique templates with additional subvariants. Non-trivial interlockings between templates with good overall coherence. 2. Random Map Events: These are events that happen randomly during the course of the mission and give an additional variance for gameplay. Examples: Random positional asteroid storm, random black holes appear on map, third party units appear and cause trouble (creepsteam),... (events like these are already implemented in aod gamemode of meta mod) 3. Map Regeneration (optional) flexibiity: We can remove all objects on the map (even tiberium fields) and set up an entirely new object/building placement configuration. Im also thinking about random maze structures and stuff like that for maximum variance and unpredictability. 4. Seed based: For procedural lua missions I thought about a wide range of mission templates that all get put together by a random seed value. The user can also use his own custom seed values. Example: MissionTemplate1 -> defend a building (seed code "DB1" - number stands for number of builidngs to defend), MissionTemplate2 -> Capture one ore more Buildings ("CB3" - number stands for number of buildings to capture), MissionTemplate3 -> guard a unit to reach a specific point on the map ("GU1" - numnber stands for number of units to guard so that they savely reach the destination"). In this case we could have a seed like "DB1CB3GU1". In addtion we could introduce another number that provides the schedule. Example addtional 1 to DB1 tells that it is the first mission objective hence DB11, so in the end we can have mission objectives run simultanously. The seed complexity could become astronomically more complex also if we add story line parts. Eventually share your seeds online and create your own missions stories by hand. Mission+Story Editor/Creator thinkable. 5. Infinite mode: Play very looong games like in age of empires with new missions continueing after each mission again and again. Adaptive difficulty could also be used. Will need a lua based savegame as due to the complexity of map and scipt manipulation standard savegames will crash the game. 6. Procedural story line (optional): A huge number of text, video, cinematic camera movement scripts and sound fragments put together for an unpredictable story with missions each time. Something I won't ever do on my own. 7. Online coop functionality. 8. Self evolutionary AI procedural mission/story director (never seen that in any videogame ever). Closest is the AI director in Left for Death 2 or FEAR but doesn't have proc contect. I'm not saying I will ever make all of this or any of this but maybe a barebone version someday. It's all technically possible and without real live I would do it. This is an inspirational post on new things we can still do to push the limits for SAGE modding. Please share your ideas on what else could be added to this idea complex and what you think about all this. Possibilities are endless.
×