|
XEditorPasteFuncs = {} |
|
|
|
function editor.SelectByClass(...) |
|
editor.ClearSel() |
|
editor.AddToSel(MapGet("map", ...) or empty_table) |
|
end |
|
|
|
function ToggleEnterExitEditor() |
|
if Platform.editor then |
|
CreateRealTimeThread(function() |
|
while IsChangingMap() or IsEditorSaving() do |
|
WaitChangeMapDone() |
|
if IsEditorSaving() then |
|
WaitMsg("SaveMapDone") |
|
end |
|
end |
|
if GetMap() == "" then |
|
print("There is no map loaded") |
|
return |
|
end |
|
if IsEditorActive() then |
|
EditorDeactivate() |
|
else |
|
EditorActivate() |
|
end |
|
end) |
|
end |
|
end |
|
|
|
function EditorViewMapObject(obj, dist, selection) |
|
local la = IsValid(obj) and obj:GetVisualPos() or InvalidPos() |
|
if la == InvalidPos() then |
|
return |
|
end |
|
if not cameraMax.IsActive() then cameraMax.Activate(1) end |
|
local cur_pos, cur_la = cameraMax.GetPosLookAt() |
|
if cur_la == cur_pos then |
|
|
|
cur_pos = cur_la - point(guim, guim, guim) |
|
end |
|
la = la:SetTerrainZ() |
|
local pos = la - SetLen(cur_la - cur_pos, (dist or 40*guim) + obj:GetRadius()) |
|
cameraMax.SetCamera(pos, la, 200, "Sin in/out") |
|
|
|
if selection then |
|
editor.ClearSel() |
|
editor.AddToSel{obj} |
|
OpenGedGameObjectEditor(editor.GetSel()) |
|
end |
|
end |
|
|
|
local objs |
|
function OnMsg.DoneMap() |
|
objs = nil |
|
end |
|
function _OpenGedGameObjectEditorInGame(reopen_only) |
|
if not GedObjectEditor then |
|
GedObjectEditor = OpenGedApp("GedObjectEditor", objs, { WarningsUpdateRoot = "root" }) or false |
|
else |
|
GedObjectEditor:UnbindObjs("root") |
|
if not reopen_only then |
|
GedObjectEditor:Call("rfnApp", "Activate") |
|
end |
|
GedObjectEditor:BindObj("root", objs) |
|
end |
|
GedObjectEditor:SelectAll("root") |
|
objs = nil |
|
end |
|
|
|
function OpenGedGameObjectEditorInGame(obj, reopen_only) |
|
if not obj or not GedObjectEditor and reopen_only then return end |
|
objs = table.create_add_unique(objs, obj) |
|
DelayedCall(0, _OpenGedGameObjectEditorInGame, reopen_only) |
|
end |
|
|
|
function CObject:AsyncCheatProperties() |
|
OpenGedGameObjectEditorInGame(self) |
|
end |
|
|
|
function OnMsg.SelectedObjChange(obj) |
|
OpenGedGameObjectEditorInGame(obj, "reopen_only") |
|
end |
|
|
|
function EditorWaitViewMapObjectByHandle(handle, map, ged) |
|
if GetMapName() ~= map then |
|
if ged then |
|
local answer = ged:WaitQuestion("Change map required!", string.format("Change map to %s?", map)) |
|
if answer ~= "ok" then |
|
return |
|
end |
|
end |
|
CloseMenuDialogs() |
|
ChangeMap(map) |
|
StoreLastLoadedMap() |
|
end |
|
EditorActivate() |
|
WaitNextFrame() |
|
local obj = HandleToObject[handle] |
|
if not IsValid(obj) then |
|
print("ERROR: no such object") |
|
return |
|
end |
|
editor.ChangeSelWithUndoRedo({obj}) |
|
EditorViewMapObject(obj) |
|
end |
|
|
|
|
|
|
|
if FirstLoad then |
|
GedSingleObjectPropEditor = false |
|
end |
|
|
|
function OpenGedSingleObjectPropEditor(obj, reopen_only) |
|
if not obj then return end |
|
CreateRealTimeThread(function() |
|
if not GedSingleObjectPropEditor and reopen_only then |
|
return |
|
end |
|
if not GedSingleObjectPropEditor then |
|
GedSingleObjectPropEditor = OpenGedApp("GedSingleObjectPropEditor", obj) or false |
|
else |
|
GedSingleObjectPropEditor:UnbindObjs("root") |
|
GedSingleObjectPropEditor:Call("rfnApp", "Activate") |
|
GedSingleObjectPropEditor:BindObj("root", obj) |
|
end |
|
end) |
|
end |
|
|
|
function OnMsg.GedClosing(ged_id) |
|
if GedSingleObjectPropEditor and GedSingleObjectPropEditor.ged_id == ged_id then |
|
GedSingleObjectPropEditor = false |
|
end |
|
end |
|
|
|
|
|
|
|
|
|
|
|
function editor.ResetZ(relative) |
|
local sel = editor:GetSel() |
|
if #sel < 1 then |
|
return |
|
end |
|
|
|
|
|
local min_z_ground = false |
|
local min_z_air = false |
|
local min_idx = false |
|
|
|
if relative then |
|
|
|
for i = 1, #sel do |
|
local obj = sel[i] |
|
|
|
local _, _, pos_z = obj:GetVisualPosXYZ() |
|
|
|
if not min_z_air or min_z_air > pos_z then |
|
min_z_air = pos_z |
|
min_idx = i |
|
end |
|
end |
|
|
|
if min_idx then |
|
local obj = sel[min_idx] |
|
|
|
local pos = obj:GetVisualPos2D() |
|
local o, z = GetWalkableObject( pos ) |
|
if o ~= nil and not IsFlagSet( obj:GetEnumFlags(), const.efWalkable ) then |
|
min_z_ground = z |
|
else |
|
min_z_ground = terrain.GetSurfaceHeight(pos) |
|
end |
|
end |
|
end |
|
|
|
SuspendPassEditsForEditOp() |
|
XEditorUndo:BeginOp{ objects = sel, name = "Snap to terrain" } |
|
for i = 1, #sel do |
|
local obj = sel[i] |
|
|
|
obj:ClearGameFlags(const.gofOnRoof) |
|
|
|
local pos = obj:GetVisualPos() |
|
local pos_z = pos:z() |
|
pos = pos:SetInvalidZ() |
|
local o, z = GetWalkableObject( pos ) |
|
|
|
if o ~= nil and not IsFlagSet( obj:GetEnumFlags(), const.efWalkable ) then |
|
if relative and min_z_air and min_z_ground then |
|
pos = point( pos:x(), pos:y(), pos_z - min_z_air + min_z_ground) |
|
else |
|
pos = point( pos:x(), pos:y()) |
|
end |
|
elseif relative and min_z_air and min_z_ground then |
|
pos = point( pos:x(), pos:y(), pos_z - min_z_air + min_z_ground) |
|
end |
|
|
|
obj:SetPos( pos ) |
|
end |
|
local objects = {} |
|
local cfEditorCallback = const.cfEditorCallback |
|
for i = 1, #sel do |
|
if sel[i]:GetClassFlags(cfEditorCallback) ~= 0 then |
|
objects[#objects + 1] = sel[i] |
|
end |
|
end |
|
if #objects > 0 then |
|
Msg("EditorCallback", "EditorCallbackMove", objects) |
|
end |
|
Msg("EditorResetZ") |
|
XEditorUndo:EndOp(sel) |
|
ResumePassEditsForEditOp() |
|
end |
|
|
|
|
|
function ObjectAnimToGameTime(object) |
|
object:SetRealtimeAnim(false) |
|
local e = object:GetEntity() |
|
if IsValidEntity(e) then |
|
object:SetAnimSpeed(1, object:GetAnimSpeed(), 0) |
|
end |
|
end |
|
|
|
function editor.GetObjectsCenter(objs) |
|
local min_z |
|
local b = box() |
|
for i = 1, #objs do |
|
local pos = objs[i]:GetPos() |
|
b = Extend(b, pos) |
|
if pos:IsValidZ() then |
|
min_z = Min(min_z or pos:z(), pos:z()) |
|
end |
|
end |
|
local center = b:Center() |
|
center = min_z and center:SetZ(min_z) or center |
|
return center |
|
end |
|
|
|
function editor.Serialize(objs, collections, center, options) |
|
local objs_orig = objs |
|
center = center or editor.GetObjectsCenter(objs) |
|
options = options or empty_table |
|
|
|
local GetVisualPosXYZ = CObject.GetVisualPosXYZ |
|
local GetHeight = terrain.GetHeight |
|
local GetTerrainNormal = terrain.GetTerrainNormal |
|
local GetOrientation = CObject.GetOrientation |
|
local IsValidZ = CObject.IsValidZ |
|
local GetClassFlags = CObject.GetClassFlags |
|
local GetGameFlags = CObject.GetGameFlags |
|
local GetCollectionIndex = CObject.GetCollectionIndex |
|
local IsValidPos = CObject.IsValidPos |
|
local cfLuaObject = const.cfLuaObject |
|
local InvalidPos = InvalidPos |
|
local IsT = IsT |
|
|
|
if not collections then |
|
collections = {} |
|
for i = 1, #objs do |
|
local col_idx = GetCollectionIndex(objs[i]) |
|
if col_idx ~= 0 then |
|
collections[col_idx] = true |
|
end |
|
end |
|
end |
|
local cols = {} |
|
for idx in pairs(collections) do |
|
cols[#cols + 1] = Collections[idx] |
|
end |
|
|
|
local cobjects |
|
if options.compact_cobjects then |
|
if objs == objs_orig then objs = table.icopy(objs) end |
|
for i = #objs,1,-1 do |
|
local obj = objs[i] |
|
if GetClassFlags(obj, cfLuaObject) == 0 then |
|
cobjects = cobjects or {} |
|
cobjects[#cobjects + 1] = obj |
|
table.remove(objs, i) |
|
end |
|
end |
|
end |
|
|
|
local get_collection_index_func |
|
local locked_idx = editor.GetLockedCollectionIdx() |
|
if locked_idx ~= 0 and not options.ignore_locked_coll then |
|
get_collection_index_func = function(obj) |
|
local idx = GetCollectionIndex(obj) |
|
if idx ~= locked_idx then |
|
return idx |
|
end |
|
end |
|
end |
|
|
|
local no_translation = options.no_translation |
|
local function get_prop(obj, prop_id) |
|
if prop_id == "CollectionIndex" and get_collection_index_func then |
|
return get_collection_index_func(obj) |
|
elseif prop_id == "Pos" then |
|
return IsValidPos(obj) and (obj:GetPos() - center) or InvalidPos() |
|
end |
|
local value = obj:GetProperty(prop_id) |
|
if no_translation and value ~= "" and IsT(value) then |
|
StoreErrorSource(obj, "Translation found for property", prop_id) |
|
return "" |
|
end |
|
return value |
|
end |
|
|
|
local code = pstr("", 1024) |
|
code:append(options.comment_tag or "--[[HGE place script]]--") |
|
code:append("\nSetObjectsCenter(") |
|
code:appendv(center) |
|
code:append(")\n") |
|
|
|
ObjectsToLuaCode(cols, code, get_prop) |
|
ObjectsToLuaCode(objs, code, get_prop) |
|
|
|
local err |
|
if cobjects then |
|
local test_encoding = options.test_encoding |
|
local collection_remap |
|
if get_collection_index_func then |
|
collection_remap = {} |
|
for _, obj in ipairs(cobjects) do |
|
collection_remap[obj] = get_collection_index_func(obj) |
|
end |
|
end |
|
code:append("\n--[[COBJECTS]]--\n") |
|
code:append("PlaceCObjects(\"") |
|
code, err = __DumpObjPropsForSave(code, cobjects, true, center, nil, nil, collection_remap, test_encoding) |
|
code:append("\")\n") |
|
end |
|
if not options.pstr then |
|
local str = code:str() |
|
code:free() |
|
code = str |
|
end |
|
return code, err |
|
end |
|
|
|
function editor.Unserialize(script, no_z, forced_center) |
|
return LuaCodeToObjs(script, { |
|
no_z = no_z, |
|
pos = forced_center or (terminal.desktop.inactive and GetTerrainGamepadCursor() or GetTerrainCursor()) |
|
}) |
|
end |
|
|
|
function editor.CopyToClipboard() |
|
if IsEditorActive() and #editor.GetSel() > 0 then |
|
local objs = editor.GetSel() |
|
local script = editor.Serialize(objs, empty_table) |
|
CopyToClipboard(script) |
|
end |
|
end |
|
|
|
function editor.PasteFromClipboard(no_z) |
|
if not IsEditorActive() then |
|
return |
|
end |
|
|
|
local script = GetFromClipboard(-1) |
|
local objs = editor.Unserialize(script, no_z) |
|
if not objs then |
|
return |
|
end |
|
|
|
objs = table.ifilter(objs, function (idx, o) return not o:IsKindOf("Collection") end) |
|
|
|
XEditorUndo:BeginOp{name = "Pasted objects"} |
|
XEditorUndo:EndOp(objs) |
|
|
|
editor.ClearSel() |
|
editor.AddToSel(objs) |
|
|
|
local objects = {} |
|
for i = 1,#objs do |
|
if IsFlagSet(objs[i]:GetClassFlags(), const.cfEditorCallback) then |
|
objects[#objects + 1] = objs[i] |
|
end |
|
end |
|
if #objects > 0 then |
|
SuspendPassEditsForEditOp() |
|
Msg("EditorCallback", "EditorCallbackPlace", objects) |
|
ResumePassEditsForEditOp() |
|
end |
|
return objs |
|
end |
|
|
|
editor.SelectDuplicates = function() |
|
local l = MapGet("map") or empty_table |
|
local num = #l |
|
|
|
print( num ) |
|
|
|
local function cmp_x(o1,o2) return o1:GetPos():x() < o2:GetPos():x() end |
|
table.sort( l, cmp_x ) |
|
|
|
editor.ClearSel() |
|
|
|
for i = 1,num do |
|
local pt = l[i]:GetPos() |
|
local axis = l[i]:GetAxis() |
|
local angle = l[i]:GetAngle() |
|
local class = l[i].class |
|
|
|
local function TestDuplicate(idx) |
|
local obj = l[idx] |
|
if pt == obj:GetPos() and axis == obj:GetAxis() and angle == obj:GetAngle() and class == obj.class then |
|
editor.AddToSel({obj}) |
|
return true |
|
end |
|
return false |
|
end |
|
|
|
local j = i + 1 |
|
local x = pt:x() |
|
while j <= num and x == l[j]:GetPos():x() do |
|
if TestDuplicate(j) then |
|
table.remove( l, j ) |
|
num = num-1 |
|
else |
|
j = j+1 |
|
end |
|
end |
|
end |
|
end |
|
|
|
local function SetReplacedObjectDefaultFlags(new_obj) |
|
new_obj:SetGameFlags(const.gofPermanent) |
|
new_obj:SetEnumFlags(const.efVisible) |
|
local entity = new_obj:GetEntity() |
|
local passability_mesh = HasMeshWithCollisionMask(entity, const.cmPassability) |
|
local entity_collisions = HasAnySurfaces(entity, EntitySurfaces.Collision) or passability_mesh |
|
local entity_apply_to_grids = HasAnySurfaces(entity, EntitySurfaces.ApplyToGrids) or passability_mesh |
|
new_obj:SetCollision(entity_collisions) |
|
new_obj:SetApplyToGrids(entity_apply_to_grids) |
|
end |
|
|
|
function editor.ReplaceObject(obj, class) |
|
if g_Classes[class] and IsValid(obj) then |
|
XEditorUndo:BeginOp{ objects = {obj}, name = "Replaced 1 objects" } |
|
Msg("EditorCallback", "EditorCallbackDelete", {obj}, "replace") |
|
local new_obj = PlaceObject(class) |
|
new_obj:CopyProperties(obj) |
|
DoneObject(obj) |
|
SetReplacedObjectDefaultFlags(new_obj) |
|
Msg("EditorCallback", "EditorCallbackPlace", {new_obj}, "replace") |
|
XEditorUndo:EndOp({new_obj}) |
|
return new_obj |
|
end |
|
return obj |
|
end |
|
|
|
function editor.ReplaceObjects(objs, class) |
|
if g_Classes[class] and #objs > 0 then |
|
SuspendPassEditsForEditOp() |
|
PauseInfiniteLoopDetection("ReplaceObjects") |
|
XEditorUndo:BeginOp{ objects = objs, name = string.format("Replaced %d objects", #objs) } |
|
Msg("EditorCallback", "EditorCallbackDelete", objs, "replace") |
|
local ol = {} |
|
for i = 1 , #objs do |
|
local new_obj = PlaceObject(class) |
|
new_obj:CopyProperties(objs[i]) |
|
DoneObject(objs[i]) |
|
SetReplacedObjectDefaultFlags(new_obj) |
|
ol[#ol + 1] = new_obj |
|
end |
|
if ol then |
|
editor.ClearSel() |
|
editor.AddToSel(ol) |
|
end |
|
Msg("EditorCallback", "EditorCallbackPlace", ol, "replace") |
|
XEditorUndo:EndOp(ol) |
|
ResumeInfiniteLoopDetection("ReplaceObjects") |
|
ResumePassEditsForEditOp() |
|
else |
|
print("No such class: " .. class) |
|
end |
|
end |
|
|
|
function OnMsg.EditorCallback(id, objects, ...) |
|
if id == "EditorCallbackClone" then |
|
local old = ... |
|
for i = 1, #old do |
|
local object = objects[i] |
|
if IsValid(object) and object:IsKindOf("EditorCallbackObject") then |
|
object:EditorCallbackClone(old[i]) |
|
end |
|
end |
|
else |
|
local place = id == "EditorCallbackPlace" |
|
local clone = id == "EditorCallbackClone" |
|
local delete = id == "EditorCallbackDelete" |
|
for i = 1, #objects do |
|
local object = objects[i] |
|
if IsValid(object) then |
|
if (place or clone) and object:IsKindOf("AutoAttachObject") and object:GetForcedLODMin() then |
|
object:SetAutoAttachMode(object:GetAutoAttachMode()) |
|
end |
|
if IsKindOf(object, "EditorCallbackObject") then |
|
object[id](object, ...) |
|
end |
|
if place then |
|
if IsKindOf(object, "EditorObject") then |
|
object:EditorEnter() |
|
end |
|
elseif delete then |
|
if IsKindOf(object, "EditorObject") then |
|
object:EditorExit() |
|
end |
|
end |
|
end |
|
end |
|
end |
|
end |
|
|
|
function editor.GetSingleSelectedCollection(objs) |
|
local collections, remaining = editor.ExtractCollections(objs or editor.GetSel()) |
|
local first = collections and next(collections) |
|
return #remaining == 0 and first and not next(collections, first) and Collections[first] |
|
end |
|
|
|
function editor.ExtractCollections(objs) |
|
local collections |
|
local remaining = {} |
|
local locked_idx = editor.GetLockedCollectionIdx() |
|
for _, obj in ipairs(objs or empty_table) do |
|
local coll_idx = 0 |
|
if obj:IsKindOf("Collection") then |
|
coll_idx = obj.Index |
|
else |
|
coll_idx = obj:GetCollectionIndex() |
|
if locked_idx ~= 0 then |
|
local relation = obj:GetCollectionRelation(locked_idx) |
|
if relation == "child" then |
|
coll_idx = 0 |
|
elseif relation == "sub" then |
|
coll_idx = Collection.GetRoot(coll_idx) |
|
end |
|
else |
|
if coll_idx ~= 0 then |
|
coll_idx = Collection.GetRoot(coll_idx) |
|
end |
|
end |
|
end |
|
|
|
if coll_idx == 0 then |
|
remaining[#remaining + 1] = obj |
|
else |
|
collections = collections or {} |
|
collections[coll_idx] = true |
|
end |
|
end |
|
return collections, remaining |
|
end |
|
|
|
function editor.SelectionPropagate(objs) |
|
local collections, selection = nil, objs or {} |
|
if XEditorSelectSingleObjects == 0 then |
|
collections, selection = editor.ExtractCollections(objs) |
|
end |
|
for coll_idx, _ in sorted_pairs(collections or empty_table) do |
|
table.iappend(selection, MapGet("map", "collection", coll_idx, true)) |
|
end |
|
|
|
if const.SlabSizeX then |
|
if terminal.IsKeyPressed(const.vkControl) then |
|
local visited = {} |
|
for _, obj in ipairs(objs) do |
|
if IsKindOf(obj, "StairSlab") and not visited[obj] then |
|
local gx, gy, gz = obj:GetGridCoords() |
|
table.iappend(selection, EnumConnectedStairSlabs(gx, gy, gz, 0, visited)) |
|
end |
|
end |
|
end |
|
end |
|
|
|
return selection |
|
end |
|
|
|
MapVar("EditorCursorObjs", {}, weak_keys_meta) |
|
PersistableGlobals.EditorCursorObjs = nil |
|
|
|
function editor.GetPlacementPoint(pt) |
|
local eye = camera.GetEye() |
|
local target = pt:SetTerrainZ() |
|
|
|
local objs = IntersectSegmentWithObjects(eye, target, const.efBuilding | const.efVisible) |
|
local pos, dist |
|
if objs then |
|
for _, obj in ipairs(objs) do |
|
if not EditorCursorObjs[obj] and obj:GetGameFlags(const.gofSolidShadow) == 0 then |
|
local hit = obj:IntersectSegment(eye, target) |
|
if hit then |
|
local d = eye:Dist(hit) |
|
if not dist or d < dist then |
|
pos, dist = hit, d |
|
end |
|
end |
|
end |
|
end |
|
end |
|
return pos or pt:SetInvalidZ() |
|
end |
|
|
|
function editor.CycleDetailClass() |
|
local sel = editor:GetSel() |
|
if #sel < 1 then |
|
return |
|
end |
|
|
|
XEditorUndo:BeginOp{ objects = sel, name = "Toggle Detail Class" } |
|
local seldc = {} |
|
for _, obj in ipairs(sel) do |
|
local dc = obj:GetDetailClass() |
|
seldc[dc] = seldc[dc] or 0 |
|
seldc[dc] = seldc[dc] + 1 |
|
end |
|
|
|
local next_dc = "Eye Candy" |
|
if seldc["Eye Candy"] then |
|
next_dc = "Optional" |
|
elseif seldc["Optional"] then |
|
next_dc = "Essential" |
|
end |
|
|
|
for _, obj in ipairs(sel) do |
|
obj:SetDetailClass(next_dc) |
|
end |
|
|
|
XEditorUndo:EndOp(sel) |
|
end |
|
|
|
function editor.ForceEyeCandy() |
|
local sel = editor:GetSel() |
|
if #sel < 1 then |
|
return |
|
end |
|
|
|
XEditorUndo:BeginOp{ objects = sel, name = "Force Eye Candy" } |
|
SuspendPassEditsForEditOp(sel) |
|
for _, obj in ipairs(sel) do |
|
obj:ClearEnumFlags(const.efCollision + const.efApplyToGrids) |
|
obj:SetDetailClass("Eye Candy") |
|
end |
|
|
|
ResumePassEditsForEditOp(sel) |
|
XEditorUndo:EndOp(sel) |
|
end |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if FirstLoad then |
|
editor.ModdingEditor = false |
|
end |
|
|
|
function editor.IsModdingEditor() |
|
return editor.ModdingEditor |
|
end |
|
|
|
function editor.AskSavingChanges() |
|
if editor.ModdingEditor and editor.ModItem and EditorMapDirty then |
|
if GedAskEverywhere("Warning", "There are unsaved changes on the map.\n\nSave before proceeding?", "Yes", "No") == "ok" then |
|
editor.ModItem:SaveMap() |
|
end |
|
SetEditorMapDirty(false) |
|
end |
|
end |
|
|
|
|
|
|
|
function OnMsg.ChangingMap(map, mapdata, handler_fns) |
|
table.insert(handler_fns, editor.AskSavingChanges) |
|
end |
|
|
|
function editor.StartModdingEditor(mod_item, map) |
|
if ChangingMap then return end |
|
|
|
editor.AskSavingChanges() |
|
|
|
editor.ModdingEditor = true |
|
editor.ModItem = mod_item |
|
editor.ModItemMap = map |
|
|
|
ReloadShortcuts() |
|
UpdateModEditorsPropPanels() |
|
|
|
if editor.PreviousModItem ~= mod_item or CurrentMap ~= map then |
|
editor.PreviousModItem = mod_item |
|
ChangeMap(map) |
|
end |
|
|
|
if not IsEditorActive() then |
|
EditorActivate() |
|
end |
|
end |
|
|
|
function editor.StopModdingEditor(return_to_mod_map) |
|
if ChangingMap or not editor.ModdingEditor then return end |
|
|
|
CreateRealTimeThread(function() |
|
|
|
if return_to_mod_map and CurrentMap ~= ModEditorMapName then |
|
editor.PreviousModItem = false |
|
ChangeMap(ModEditorMapName) |
|
end |
|
|
|
editor.ModdingEditor = false |
|
editor.ModItem = nil |
|
editor.ModItemMap = nil |
|
|
|
ReloadShortcuts() |
|
UpdateModEditorsPropPanels() |
|
|
|
if IsEditorActive() then |
|
EditorDeactivate() |
|
end |
|
end) |
|
end |
|
|
|
function OnMsg.GedClosing(ged_id) |
|
local conn = GedConnections[ged_id] |
|
if conn and conn.app_template == "ModEditor" then |
|
if editor.ModdingEditor and editor.ModItem and conn.bound_objects.root[1] == editor.ModItem.mod then |
|
editor.StopModdingEditor("return to mod map") |
|
end |
|
end |
|
end |
|
|
|
|
|
function OnMsg.ChangeMap(map) |
|
if editor.ModdingEditor and editor.ModItemMap ~= map then |
|
editor.ModItemMap = nil |
|
editor.ModItem = nil |
|
for _, mod in ipairs(ModsLoaded) do |
|
mod:ForEachModItem(function(mod_item) |
|
if mod_item:GetMapName() == map then |
|
editor.ModItem = mod_item |
|
return "break" |
|
end |
|
end) |
|
end |
|
UpdateModEditorsPropPanels() |
|
end |
|
end |
|
|