Jump to content

Mjjstral

Members
  • Content count

    105
  • Joined

  • Last visited

Community Reputation

22 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,794 profile views
  1. 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).
  2. 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
  3. 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
  4. 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.
  5. 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).
  6. 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 ?
  7. 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).
  8. 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
  9. 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)]))
  10. 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).
  11. 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.
  12. Yes it's possible in many variants I can think of (mostly lua heavy solutions): 1. Variant - AI Co-Control: This let's an hard ai co control the human players faction side by side. Change MakeAllSkirmishSidesAIControlled = No to Yes in skirmishaidata.ini. You can also make it toggleable e.g. via a playerpower button and with help of lua so that the ai only becomes active if the player wishes to. That's something I had running in the past and it worked great but not for custom factions unfortunately (crashes) that's why I needed to disable it in MetaMod. You could also make an ability to select certain buildings/units during game that the ai then won't control anymore if you wish (via lua) 2. Variant - One basebuilder and one Unit controller: Units get transfered immediately to the other player on creation via lua. A "victory condition dummy" and custom victory condition lua scipts ensure correct win/lose conditions as one player doesn't own any buildings. The sides can even be made switchable and if both players are humans you can even implement an accept/deny button. 3. Variant - see MetaMod diplomacy options menu: "temporary switch sides", "temporary give control to another player", "temporary take control of another player" (with accept/deny button in case of human player). All these options are toggleable. New units created will still belong to the player who created them but that could also be changed if needed. 4. Variant - not recommended: A lua co routine checks every x ms if a player has selected a unit or building of the allied player. If so the unit gets immidiately transfered and tranfereed back after unselect so that it's not noticeable. Downside: Short selection keys (q,w...) need to be replaced by an additonal selection menu. But these menu entries can have keys assigned themselves. Group assignment won't work here except if you also make menu entries that trigger lua selection scripts for that. 5. Everything inbetween - mixture of thes variants. Just as an interesting sidennote: We can use 4 more players/teams that are always available regardless of the playercount: Lua Team Names: NeutralTeam="/team" CivilianTeam="PlyrCivilian/teamPlyrCivilian" CreepsTeam="PlyrCreeps/teamPlyrCreeps" ObserverTeam="ReplayObserver/teamReplayObserver" I use the CreepsTeam (always enemy to all) e.g. for my art of defense gamemodes, so we don't need another dummy ai player. CivilianTeam,NeutralTeam or ObserverTeam could be used as an artificiall ally. You could totally program an independent lua ai for these to support the player too. But it's a loooot of work.
  13. Regarding the lua command: The last parameter (percentage of horde) is missing: ExecuteAction("UNIT_SET_MODELCONDITION_FOR_DURATION", self, "USER_17", "4", "100") And for numbers it doesn't matter if you use quotation marked numbers or pure numbers. It gets converted to double values on the c side of the lua c api nontheless.
  14. I invite all of you to the new SAGE Engine Modding discord server with seperate channels for each game. Basically for every good modding community nowadays there is a discord server so I had to create one. Invite all SAGE modders you know so that we can quickly grow. Thank's !!! I still need at least 2 more moderators so just contact me for that if you like to do it https://discord.gg/TfdcQTn
  15. You could make a simple batch script with/and/or use of some regex replacements.
×