Remove Atlas UI scripting support
This was SVN commit r9567.
This commit is contained in:
parent
dc2035efc9
commit
a81f180dd6
@ -1,139 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Terrain preview page
|
||||
//
|
||||
// Used by new dialog and terrain panel
|
||||
|
||||
global.TerrainPreviewPage = function(panel, name, width, height)
|
||||
{
|
||||
this.panel = panel;
|
||||
this.name = name;
|
||||
|
||||
// Size of texture preview images
|
||||
this.w = width ? width : 120
|
||||
this.h = height ? height : 40;
|
||||
|
||||
this.lastTerrainSelection = null; // button that was last selected, so we can undo its colouring
|
||||
this.previewReloadTimer = null;
|
||||
}
|
||||
|
||||
global.TerrainPreviewPage.prototype = {
|
||||
reloadPreviews: function()
|
||||
{
|
||||
this.panel.freeze();
|
||||
this.scrolled.destroyChildren();
|
||||
this.itemSizer.clear();
|
||||
|
||||
this.lastTerrainSelection = null; // clear any reference to deleted window
|
||||
|
||||
var previews = Atlas.Message.GetTerrainGroupPreviews(this.name, this.w, this.h).previews;
|
||||
var i = 0;
|
||||
var names = [];
|
||||
var allLoaded = true;
|
||||
for each (var p in previews)
|
||||
{
|
||||
if (!p.loaded)
|
||||
{
|
||||
allLoaded = false;
|
||||
}
|
||||
|
||||
// Create a wrapped-text label (replacing '_' with ' ' so there are more wrapping opportunities)
|
||||
var labelText = p.name.replace(/_/g, ' ');
|
||||
var label = new wxStaticText(this.scrolled, -1, labelText, wxDefaultPosition, wxDefaultSize, wxStaticText.ALIGN_CENTER);
|
||||
label.wrap(this.w);
|
||||
|
||||
var imgSizer = new wxBoxSizer(wxOrientation.VERTICAL);
|
||||
var button = new wxBitmapButton(this.scrolled, -1, p.imagedata);
|
||||
var self = this;
|
||||
button.terrainName = p.name;
|
||||
button.onClicked = function()
|
||||
{
|
||||
Atlas.SetSelectedTexture(this.terrainName);
|
||||
if (self.lastTerrainSelection)
|
||||
{
|
||||
self.lastTerrainSelection.backgroundColour = wxNullColour;
|
||||
}
|
||||
this.backgroundColour = new wxColour(255, 255, 0);
|
||||
self.lastTerrainSelection = this;
|
||||
};
|
||||
imgSizer.add(button, 0, wxAlignment.CENTRE);
|
||||
imgSizer.add(label, 1, wxAlignment.CENTRE);
|
||||
this.itemSizer.add(imgSizer, 0, wxAlignment.CENTRE | wxStretch.EXPAND);
|
||||
}
|
||||
this.itemSizer.layout();
|
||||
this.panel.layout();
|
||||
this.panel.thaw();
|
||||
|
||||
// If not all textures were loaded yet, run a timer to reload the previews
|
||||
// every so often until they've all finished
|
||||
if (allLoaded && this.previewReloadTimer)
|
||||
{
|
||||
this.previewReloadTimer.stop();
|
||||
this.previewReloadTimer = null;
|
||||
}
|
||||
else if (!allLoaded && !this.previewReloadTimer)
|
||||
{
|
||||
this.previewReloadTimer = new wxTimer();
|
||||
var self = this;
|
||||
this.previewReloadTimer.onNotify = function() { self.reloadPreviews(); };
|
||||
this.previewReloadTimer.start(2000);
|
||||
}
|
||||
},
|
||||
|
||||
display: function()
|
||||
{
|
||||
if (this.loaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.panel.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
|
||||
var scrolled = new wxScrolledWindow(this.panel, -1, wxDefaultPosition, wxDefaultSize, wxWindow.VSCROLL);
|
||||
scrolled.setScrollRate(0, 10);
|
||||
scrolled.backgroundColour = new wxColour(255, 255, 255);
|
||||
this.panel.sizer.add(scrolled, 1, wxStretch.EXPAND);
|
||||
|
||||
var itemSizer = new wxGridSizer(6, 4, 0);
|
||||
scrolled.sizer = itemSizer;
|
||||
|
||||
// Adjust the number of columns to fit in the available area
|
||||
var w = this.w;
|
||||
scrolled.onSize = function (evt)
|
||||
{
|
||||
var numCols = Math.max(1, Math.floor(evt.size.width / (w+16)));
|
||||
if (itemSizer.cols != numCols)
|
||||
{
|
||||
itemSizer.cols = numCols;
|
||||
}
|
||||
};
|
||||
|
||||
this.scrolled = scrolled;
|
||||
this.itemSizer = itemSizer;
|
||||
this.reloadPreviews();
|
||||
|
||||
// TODO: fix keyboard navigation of the terrain previews
|
||||
|
||||
this.loaded = true;
|
||||
}
|
||||
};
|
||||
|
||||
global.TerrainPreviewNotebook = function(window)
|
||||
{
|
||||
var terrainGroups = Atlas.Message.GetTerrainGroups();
|
||||
var nb = new wxNotebook(window, -1);
|
||||
window.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
|
||||
window.sizer.add(nb, 1, wxStretch.EXPAND);
|
||||
|
||||
var pages = [];
|
||||
nb.onPageChanged = function (evt)
|
||||
{
|
||||
pages[evt.selection].display()
|
||||
evt.skip = true;
|
||||
}
|
||||
for each (var groupName in terrainGroups.groupNames)
|
||||
{
|
||||
var panel = new wxPanel(nb, -1);
|
||||
var page = new global.TerrainPreviewPage(panel, groupName);
|
||||
pages.push(page);
|
||||
nb.addPage(panel, groupName); // TODO: use Titlecase letters
|
||||
}
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
Atlas.RenderView = {
|
||||
GAME: 1,
|
||||
ACTOR: 2
|
||||
}; // TODO: this should probably be defined by the C++ code
|
||||
|
||||
// Define the default state settings.
|
||||
// (It's done this way so that this script can be dynamically reloaded,
|
||||
// and won't overwrite the previous runtime state but will still pick
|
||||
// up any new properties)
|
||||
var defaults = {
|
||||
objectSettings: {
|
||||
view: Atlas.RenderView.GAME,
|
||||
selectedObjects: [],
|
||||
playerID: 1,
|
||||
actorSelections: [],
|
||||
variantgroups: []
|
||||
}
|
||||
};
|
||||
|
||||
defaults.objectSettings.toSObjectSettings = function () {
|
||||
return {
|
||||
player: this.playerID,
|
||||
selections: this.actorSelections
|
||||
};
|
||||
}
|
||||
|
||||
defaults.objectSettings.onSelectionChange = function () {
|
||||
if (! this.selectedObjects.length) {
|
||||
// TODO: do something sensible here
|
||||
this.actorSelections = [];
|
||||
this.variantgroups = [];
|
||||
} else {
|
||||
// TODO: Support multiple selections
|
||||
var selection = this.selectedObjects[0];
|
||||
|
||||
var settings = Atlas.Message.GetObjectSettings(this.view, selection).settings;
|
||||
|
||||
if (settings.player != -1)
|
||||
this.playerID = settings.player;
|
||||
this.actorSelections = settings.selections;
|
||||
this.variantgroups = settings.variantgroups;
|
||||
}
|
||||
this.notifyObservers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current actor variation (as a list of chosen variants), based
|
||||
* on its variant groups and the selection strings. This is equivalent to the
|
||||
* variation rendered by the game.
|
||||
*/
|
||||
defaults.objectSettings.getActorVariation = function ()
|
||||
{
|
||||
var selectionMap = {};
|
||||
for each (var s in this.actorSelections)
|
||||
selectionMap[s] = 1;
|
||||
|
||||
var variation = [];
|
||||
GROUP: for each (var group in this.variantgroups) {
|
||||
for each (var variant in group) {
|
||||
if (variant in selectionMap) {
|
||||
variation.push(variant);
|
||||
continue GROUP;
|
||||
}
|
||||
}
|
||||
// None selected; default to first
|
||||
variation.push(group[0]);
|
||||
}
|
||||
return variation;
|
||||
}
|
||||
|
||||
// Merges the 'defs' tree into 'obj', overwriting any old values with
|
||||
// the same keys
|
||||
function setDefaults(defs, obj)
|
||||
{
|
||||
for (var k in defs) {
|
||||
if (k in obj)
|
||||
setDefaults(defs[k], obj[k]);
|
||||
else
|
||||
obj[k] = defaults[k];
|
||||
}
|
||||
}
|
||||
|
||||
function makeObservable(obj)
|
||||
{
|
||||
// If the object has already been set up as observable, don't do any more work.
|
||||
// (In particular, don't delete any old observers, so they don't get lost when
|
||||
// this script is reloaded.)
|
||||
if (typeof obj._observers != 'undefined')
|
||||
return;
|
||||
|
||||
obj._observers = [];
|
||||
obj.registerObserver = function (callback) {
|
||||
this._observers.push(callback);
|
||||
}
|
||||
obj.unregisterObserver = function (callback) {
|
||||
this._observers = this._observers.filter(function (o) { return o !== callback });
|
||||
}
|
||||
obj.notifyObservers = function () {
|
||||
for each (var o in this._observers)
|
||||
o(this);
|
||||
};
|
||||
}
|
||||
|
||||
function postObjectSettingsToGame(objectSettings)
|
||||
{
|
||||
// TODO: if view != GAME, we don't really want this to be an undoable command
|
||||
if (objectSettings.selectedObjects.length)
|
||||
Atlas.Message.SetObjectSettings(objectSettings.view,
|
||||
objectSettings.selectedObjects[0], objectSettings.toSObjectSettings());
|
||||
}
|
||||
|
||||
function init()
|
||||
{
|
||||
setDefaults(defaults, Atlas.State);
|
||||
|
||||
makeObservable(Atlas.State.objectSettings);
|
||||
Atlas.State.objectSettings.registerObserver(postObjectSettingsToGame);
|
||||
}
|
||||
|
||||
function deinit() {
|
||||
Atlas.State.objectSettings.unregisterObserver(postObjectSettingsToGame);
|
||||
}
|
||||
|
@ -1,139 +0,0 @@
|
||||
function getScriptFilename(name)
|
||||
{
|
||||
var relativePath = 'tools/atlas/scripts/' + name + '.js';
|
||||
var filename = new wxFileName(relativePath, wxPathFormat.UNIX);
|
||||
filename.normalize(wxPathNormalize.DOTS | wxPathNormalize.ABSOLUTE | wxPathNormalize.TILDE,
|
||||
Atlas.GetDataDirectory()); // equivalent to MakeAbsolute(dir);
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and executes a script from disk. The script runs in a separate scope,
|
||||
* so variables and functions declared in it will not be visible outside that file.
|
||||
*/
|
||||
function loadScript(name /*, ...*/)
|
||||
{
|
||||
var filename = getScriptFilename(name);
|
||||
var file = new wxFFile(filename.fullPath);
|
||||
var script = file.readAll(); // TODO: handle errors
|
||||
file.close();
|
||||
|
||||
var script = Atlas.LoadScript(name+'.js', script);
|
||||
|
||||
// Extract the arguments which the function will actually use
|
||||
// (Can't use Array.slice since arguments isn't an Array)
|
||||
// (Have to do this rather than use arguments.length, since we sometimes
|
||||
// pass unused bottomWindows into init and then destroy the window when realising
|
||||
// it wasn't used, and then we mustn't send the destroyed window again later)
|
||||
var args = [];
|
||||
if (script.init)
|
||||
for (var i = 1; i < 1+script.init.length; ++i)
|
||||
args.push(arguments[i]);
|
||||
|
||||
scriptReloader.add(name, args, filename, script);
|
||||
|
||||
if (script.init)
|
||||
script.init.apply(null, args);
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for C++ to easily set dot-separated names
|
||||
*/
|
||||
function setValue(name, value)
|
||||
{
|
||||
var obj = global;
|
||||
var props = name.split(".");
|
||||
for (var i = 0; i < props.length-1; ++i)
|
||||
obj = obj[props[i]];
|
||||
obj[props[props.length-1]] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for C++ to easily get dot-separated names
|
||||
*/
|
||||
function getValue(name)
|
||||
{
|
||||
var obj = global;
|
||||
var props = name.split(".");
|
||||
for (var i = 0; i < props.length; ++i)
|
||||
obj = obj[props[i]];
|
||||
return obj;
|
||||
}
|
||||
|
||||
function loadXML(name)
|
||||
{
|
||||
var relativePath = 'tools/atlas/' + name + '.xml';
|
||||
var filename = new wxFileName(relativePath, wxPathFormat.UNIX);
|
||||
filename.normalize(wxPathNormalize.DOTS | wxPathNormalize.ABSOLUTE | wxPathNormalize.TILDE,
|
||||
Atlas.GetDataDirectory()); // equivalent to MakeAbsolute(dir);
|
||||
|
||||
var file = new wxFFile(filename.fullPath);
|
||||
var xml = file.readAll(); // TODO: handle errors
|
||||
// TODO: complain (or work) nicely if the XML file starts with
|
||||
// "<?xml ...?>" (which E4X doesn't like parsing)
|
||||
file.close();
|
||||
|
||||
return new XML(xml);
|
||||
}
|
||||
|
||||
// Automatically reload scripts from disk when they have been modified
|
||||
var scriptReloader = {
|
||||
timer: new wxTimer(),
|
||||
scripts: [], // [ {name, args, filename, mtime, window, script}, ... ]
|
||||
notify: function ()
|
||||
{
|
||||
for each (var script in scriptReloader.scripts)
|
||||
{
|
||||
var mtime = script.filename.modificationTime;
|
||||
if (mtime - script.mtime != 0)
|
||||
{
|
||||
print('*** Modifications detected - reloading "' + script.name + '"...\n');
|
||||
|
||||
script.mtime = mtime;
|
||||
|
||||
if (script.script && script.script.deinit)
|
||||
script.script.deinit();
|
||||
|
||||
if (script.name == 'main')
|
||||
{
|
||||
// Special case for this file to reload itself
|
||||
script.script = loadScript(script.name, null);
|
||||
// Copy the important state into the new version of this file
|
||||
script.script.scriptReloader.scripts = scriptReloader.scripts;
|
||||
// Stop this one
|
||||
scriptReloader.timer.stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: know which arguments are really windows that should be regenerated
|
||||
for each (var window in script.args)
|
||||
window.destroyChildren();
|
||||
script.script = loadScript.apply(null, [script.name].concat(script.args));
|
||||
for each (var window in script.args)
|
||||
window.layout();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
add: function (name, args, filename, script)
|
||||
{
|
||||
for each (var s in this.scripts)
|
||||
if (s.name == name)
|
||||
return; // stop if this is already loaded
|
||||
|
||||
this.scripts.push({ name:name, args:args, filename:filename, mtime:filename.modificationTime, script:script });
|
||||
}
|
||||
};
|
||||
scriptReloader.timer.onNotify = scriptReloader.notify;
|
||||
scriptReloader.timer.start(1000);
|
||||
scriptReloader.add('main', null, getScriptFilename('main'));
|
||||
|
||||
loadScript('editorstate');
|
||||
|
||||
// Export global functions:
|
||||
global.loadScript = loadScript;
|
||||
global.loadXML = loadXML;
|
||||
global.setValue = setValue;
|
||||
global.getValue = getValue;
|
@ -1,552 +0,0 @@
|
||||
|
||||
function setupSimTest(window, rmsPanel)
|
||||
{
|
||||
var state = 'inactive'; // inactive, playing
|
||||
var speed = 0;
|
||||
|
||||
function play(newSpeed)
|
||||
{
|
||||
if (state == 'inactive')
|
||||
{
|
||||
Atlas.Message.SimStateSave('default');
|
||||
Atlas.Message.GuiSwitchPage('page_session.xml');
|
||||
}
|
||||
Atlas.Message.SimPlay(newSpeed);
|
||||
state = 'playing';
|
||||
speed = newSpeed;
|
||||
updateEnableStatus();
|
||||
}
|
||||
|
||||
function reset()
|
||||
{
|
||||
if (state == 'playing')
|
||||
{
|
||||
Atlas.Message.SimStateRestore('default');
|
||||
Atlas.Message.GuiSwitchPage('page_atlas.xml');
|
||||
}
|
||||
Atlas.Message.SimPlay(0);
|
||||
state = 'inactive';
|
||||
speed = 0;
|
||||
updateEnableStatus();
|
||||
}
|
||||
|
||||
function updateEnableStatus()
|
||||
{
|
||||
for (var i in buttons)
|
||||
{
|
||||
buttons[i][3].enable = buttons[i][2]();
|
||||
}
|
||||
|
||||
if (state == 'playing')
|
||||
{
|
||||
// Disable RMS controls
|
||||
rmsPanel.enable = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
rmsPanel.enable = true;
|
||||
}
|
||||
}
|
||||
|
||||
var speeds = [ 1/8, 1, 8 ];
|
||||
|
||||
var buttons = [
|
||||
/* button label; click command; active condition */
|
||||
[ 'Play', function () { play(speeds[1]) }, function () { return !(state == 'playing' && speed == speeds[1]) } ],
|
||||
[ 'Fast', function () { play(speeds[2]) }, function () { return !(state == 'playing' && speed == speeds[2]) } ],
|
||||
[ 'Slow', function () { play(speeds[0]) }, function () { return !(state == 'playing' && speed == speeds[0]) } ],
|
||||
[ 'Pause', function () { play(0) }, function () { return state == 'playing' && speed != 0 } ],
|
||||
[ 'Reset', function () { reset() }, function () { return state != 'inactive' } ],
|
||||
];
|
||||
|
||||
var sizer = new wxStaticBoxSizer(new wxStaticBox(window, -1, 'Simulation test'), wxOrientation.HORIZONTAL);
|
||||
for each (var b in buttons)
|
||||
{
|
||||
var button = new wxButton(window, -1, b[0]);
|
||||
button.onClicked = b[1];
|
||||
sizer.add(button, 1);
|
||||
b[3] = button;
|
||||
}
|
||||
updateEnableStatus();
|
||||
window.sizer.add(sizer, 0, wxStretch.EXPAND | wxDirection.LEFT|wxDirection.RIGHT, 2);
|
||||
|
||||
}
|
||||
|
||||
//TODO: Would be nicer not to use an extra settings property, this is to avoid the observer data getting written to maps
|
||||
// perhaps that single element can be excluded
|
||||
var defaults = {
|
||||
mapSettings : {
|
||||
settings: {
|
||||
Name: 'Untitled',
|
||||
Description : '',
|
||||
PlayerData : []
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var g_observer;
|
||||
|
||||
// Flag if we should only notify other scripts not this one (prevents recursion)
|
||||
var g_externalNotify;
|
||||
|
||||
// Merges the 'defs' tree into 'obj', overwriting any old values with
|
||||
// the same keys
|
||||
function setDefaults(defs, obj)
|
||||
{
|
||||
if (defs instanceof Object)
|
||||
{
|
||||
for (var k in defs) {
|
||||
if (obj instanceof Object && k in obj)
|
||||
setDefaults(defs[k], obj[k]);
|
||||
else
|
||||
obj[k] = defs[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read civ data and player defaults
|
||||
function loadCivData()
|
||||
{
|
||||
// Load civilization data
|
||||
Atlas.State.CivData = [];
|
||||
Atlas.State.CivNames = [];
|
||||
Atlas.State.CivCodes = [];
|
||||
|
||||
var dataArray = Atlas.Message.GetCivData().data;
|
||||
if (dataArray)
|
||||
{ // parse JSON strings into objects
|
||||
for (var i = 0; i < dataArray.length; ++i)
|
||||
{
|
||||
var civ = JSON.parse(dataArray[i]);
|
||||
if (civ)
|
||||
{
|
||||
Atlas.State.CivData.push(civ);
|
||||
Atlas.State.CivNames.push(civ.Name);
|
||||
Atlas.State.CivCodes.push(civ.Code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadPlayerDefaults()
|
||||
{
|
||||
// Load player default data (names, civs, colors, etc)
|
||||
Atlas.State.PlayerDefaults = [];
|
||||
|
||||
var rawData = Atlas.Message.GetPlayerDefaults().defaults;
|
||||
if(rawData)
|
||||
{
|
||||
Atlas.State.PlayerDefaults = JSON.parse(rawData).PlayerData;
|
||||
}
|
||||
}
|
||||
|
||||
function getMapSettings()
|
||||
{
|
||||
// Get map settings to populate GUI
|
||||
var settings = Atlas.Message.GetMapSettings().settings;
|
||||
if (settings)
|
||||
{
|
||||
Atlas.State.mapSettings.settings = JSON.parse(settings);
|
||||
}
|
||||
}
|
||||
|
||||
function makeObservable(obj)
|
||||
{
|
||||
// If the object has already been set up as observable, don't do any more work.
|
||||
// (In particular, don't delete any old observers, so they don't get lost when
|
||||
// this script is reloaded.)
|
||||
if (typeof obj._observers != 'undefined')
|
||||
return;
|
||||
|
||||
obj._observers = [];
|
||||
obj.registerObserver = function (callback) {
|
||||
this._observers.push(callback);
|
||||
}
|
||||
obj.unregisterObserver = function (callback) {
|
||||
this._observers = this._observers.filter(function (o) { return o !== callback });
|
||||
}
|
||||
obj.notifyObservers = function () {
|
||||
for each (var o in this._observers)
|
||||
o(this);
|
||||
};
|
||||
}
|
||||
|
||||
function init(window)
|
||||
{
|
||||
window.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
|
||||
|
||||
// Don't overwrite old data when script is hotloaded
|
||||
setDefaults(defaults, Atlas.State);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Map setting controls
|
||||
// Map name
|
||||
var settingsSizer = new wxStaticBoxSizer(new wxStaticBox(window, -1, 'Map settings'), wxOrientation.VERTICAL);
|
||||
var boxSizer = new wxBoxSizer(wxOrientation.HORIZONTAL);
|
||||
boxSizer.add(new wxStaticText(window, -1, 'Name'), 0, wxAlignment.CENTER_VERTICAL);
|
||||
boxSizer.add(10, 0);
|
||||
var mapNameCtrl = new wxTextCtrl(window, -1, 'Untitled');
|
||||
mapNameCtrl.toolTip = "Enter a name for the map here";
|
||||
mapNameCtrl.onText = function(evt)
|
||||
{
|
||||
Atlas.State.mapSettings.settings.Name = evt.string;
|
||||
};
|
||||
boxSizer.add(mapNameCtrl, 1);
|
||||
function updateMapName()
|
||||
{
|
||||
mapNameCtrl.value = Atlas.State.mapSettings.settings.Name ? Atlas.State.mapSettings.settings.Name : 'Untitled';
|
||||
}
|
||||
settingsSizer.add(boxSizer, 0, wxStretch.EXPAND);
|
||||
|
||||
settingsSizer.add(5, 5, 0); // Add space
|
||||
|
||||
// Map description
|
||||
boxSizer = new wxBoxSizer(wxOrientation.VERTICAL);
|
||||
boxSizer.add(new wxStaticText(window, -1, 'Description'), wxAlignment.RIGHT);
|
||||
var mapDescCtrl = new wxTextCtrl(window, -1, '', wxDefaultPosition, new wxSize(-1, 100), wxTextCtrl.MULTILINE);
|
||||
mapDescCtrl.toolTip = "Enter an interesting description for the map here";
|
||||
mapDescCtrl.onText = function(evt)
|
||||
{
|
||||
Atlas.State.mapSettings.settings.Description = evt.string;
|
||||
};
|
||||
boxSizer.add(mapDescCtrl, 0, wxStretch.EXPAND);
|
||||
function updateMapDesc()
|
||||
{
|
||||
mapDescCtrl.value = Atlas.State.mapSettings.settings.Description ? Atlas.State.mapSettings.settings.Description : '';
|
||||
}
|
||||
settingsSizer.add(boxSizer, 0, wxStretch.EXPAND);
|
||||
|
||||
settingsSizer.add(5, 5, 0); // Add space
|
||||
|
||||
// Reveal map
|
||||
boxSizer = new wxBoxSizer(wxOrientation.HORIZONTAL);
|
||||
boxSizer.add(new wxStaticText(window, -1, 'Reveal map'), wxAlignment.LEFT);
|
||||
boxSizer.add(10, 0);
|
||||
var revealMapCtrl = new wxCheckBox(window, -1, '');
|
||||
revealMapCtrl.toolTip = 'If checked, players will see the whole map explored and their enemies';
|
||||
revealMapCtrl.onCheckBox = function(evt)
|
||||
{
|
||||
Atlas.State.mapSettings.settings.RevealMap = evt.checked;
|
||||
};
|
||||
boxSizer.add(revealMapCtrl);
|
||||
function updateRevealMap()
|
||||
{ // Defaults to false if setting doesn't exist
|
||||
revealMapCtrl.value = Atlas.State.mapSettings.settings.RevealMap;
|
||||
}
|
||||
settingsSizer.add(boxSizer, 0, wxStretch.EXPAND);
|
||||
|
||||
settingsSizer.add(5, 5, 0); // Add space
|
||||
|
||||
// Game type
|
||||
boxSizer = new wxBoxSizer(wxOrientation.HORIZONTAL);
|
||||
boxSizer.add(new wxStaticText(window, -1, 'Game type'), 0, wxAlignment.CENTER_VERTICAL);
|
||||
boxSizer.add(10, 0);
|
||||
var gameTypes = ["conquest", "endless"];
|
||||
var gameTypeCtrl = new wxChoice(window, -1, wxDefaultPosition, new wxSize(100,-1), gameTypes);
|
||||
gameTypeCtrl.toolTip = 'Select the game type / victory conditions';
|
||||
gameTypeCtrl.onChoice = function (evt)
|
||||
{
|
||||
if (evt.selection != -1)
|
||||
{
|
||||
Atlas.State.mapSettings.settings.GameType = evt.string;
|
||||
}
|
||||
};
|
||||
boxSizer.add(gameTypeCtrl);
|
||||
function updateGameType()
|
||||
{
|
||||
var idx = Atlas.State.mapSettings.settings.GameType ? gameTypes.indexOf(Atlas.State.mapSettings.settings.GameType) : 0;
|
||||
gameTypeCtrl.selection = idx;
|
||||
}
|
||||
settingsSizer.add(boxSizer, 0, wxStretch.EXPAND);
|
||||
|
||||
settingsSizer.add(5, 5, 0); // Add space
|
||||
|
||||
// Number of players
|
||||
boxSizer = new wxBoxSizer(wxOrientation.HORIZONTAL);
|
||||
boxSizer.add(new wxStaticText(window, -1, 'Number of Players'), 0, wxAlignment.CENTER_VERTICAL);
|
||||
boxSizer.add(10, 0);
|
||||
var numPlayers = new wxSpinCtrl(window, -1, '8', wxDefaultPosition, new wxSize(40, -1));
|
||||
numPlayers.toolTip = 'Select the number of players on this map';
|
||||
numPlayers.setRange(1, 8);
|
||||
numPlayers.onSpinCtrl = function(evt)
|
||||
{
|
||||
// Adjust player data accordingly
|
||||
if (!Atlas.State.mapSettings.settings.PlayerData)
|
||||
Atlas.State.mapSettings.settings.PlayerData = [];
|
||||
|
||||
Atlas.State.numPlayers = evt.position;
|
||||
var curPlayers = Atlas.State.mapSettings.settings.PlayerData.length;
|
||||
|
||||
if (curPlayers < evt.position)
|
||||
{ // Add extra players from default
|
||||
for (var i = curPlayers; i < evt.position; ++i)
|
||||
{
|
||||
Atlas.State.mapSettings.settings.PlayerData.push(Atlas.State.PlayerDefaults[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //Remove extra players
|
||||
Atlas.State.mapSettings.settings.PlayerData = Atlas.State.mapSettings.settings.PlayerData.slice(0, evt.position);
|
||||
}
|
||||
|
||||
g_externalNotify = true;
|
||||
Atlas.State.mapSettings.notifyObservers();
|
||||
g_externalNotify = false;
|
||||
};
|
||||
boxSizer.add(numPlayers);
|
||||
function updateNumPlayers()
|
||||
{
|
||||
numPlayers.value = Atlas.State.mapSettings.settings.PlayerData ? Atlas.State.mapSettings.settings.PlayerData.length : 8;
|
||||
}
|
||||
settingsSizer.add(boxSizer, 0, wxStretch.EXPAND);
|
||||
|
||||
window.sizer.add(settingsSizer, 0, wxStretch.EXPAND | wxDirection.LEFT|wxDirection.RIGHT, 2);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Keyword list
|
||||
var keywordSizer = new wxStaticBoxSizer(new wxStaticBox(window, -1, 'Keywords'), wxOrientation.VERTICAL);
|
||||
|
||||
boxSizer = new wxBoxSizer(wxOrientation.HORIZONTAL);
|
||||
boxSizer.add(new wxStaticText(window, -1, 'Demo'));
|
||||
boxSizer.add(5, 0);
|
||||
var demoCtrl = new wxCheckBox(window, -1, '');
|
||||
demoCtrl.tooltip = 'Toggle \'demo\' keyword';
|
||||
demoCtrl.onCheckBox = function(evt)
|
||||
{
|
||||
applyKeyword(evt.checked, 'demo');
|
||||
};
|
||||
boxSizer.add(demoCtrl);
|
||||
keywordSizer.add(boxSizer, 0, wxStretch.EXPAND);
|
||||
keywordSizer.add(0, 5);
|
||||
|
||||
boxSizer = new wxBoxSizer(wxOrientation.HORIZONTAL);
|
||||
boxSizer.add(new wxStaticText(window, -1, 'Hidden'));
|
||||
boxSizer.add(5, 0);
|
||||
var hiddenCtrl = new wxCheckBox(window, -1, '');
|
||||
hiddenCtrl.tooltip = 'Toggle \'hidden\' keyword';
|
||||
hiddenCtrl.onCheckBox = function(evt)
|
||||
{
|
||||
applyKeyword(evt.checked, 'hidden');
|
||||
};
|
||||
boxSizer.add(hiddenCtrl);
|
||||
keywordSizer.add(boxSizer, 0, wxStretch.EXPAND);
|
||||
|
||||
function applyKeyword(flag, keyword)
|
||||
{
|
||||
var idx = Atlas.State.mapSettings.settings.Keywords.indexOf(keyword);
|
||||
if (flag && idx == -1)
|
||||
{ // Add keyword
|
||||
Atlas.State.mapSettings.settings.Keywords.push(keyword);
|
||||
}
|
||||
else if (!flag && idx != -1)
|
||||
{ // Remove keyword
|
||||
Atlas.State.mapSettings.settings.Keywords.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
function updateKeywords()
|
||||
{
|
||||
if (!Atlas.State.mapSettings.settings.Keywords)
|
||||
{
|
||||
Atlas.State.mapSettings.settings.Keywords = [];
|
||||
}
|
||||
|
||||
demoCtrl.value = (Atlas.State.mapSettings.settings.Keywords && Atlas.State.mapSettings.settings.Keywords.indexOf('demo') != -1);
|
||||
hiddenCtrl.value = (Atlas.State.mapSettings.settings.Keywords && Atlas.State.mapSettings.settings.Keywords.indexOf('hidden') != -1);
|
||||
}
|
||||
|
||||
window.sizer.add(keywordSizer, 0, wxStretch.EXPAND | wxDirection.LEFT|wxDirection.RIGHT, 2);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Random map controls
|
||||
var rmsPanel = new wxPanel(window, -1);
|
||||
var rmsSizer = new wxStaticBoxSizer(new wxStaticBox(rmsPanel, -1, 'Random map'), wxOrientation.VERTICAL);
|
||||
|
||||
boxSizer = new wxBoxSizer(wxOrientation.HORIZONTAL);
|
||||
var rmsChoice = new wxChoice(rmsPanel, -1, wxDefaultPosition, wxDefaultSize, []);
|
||||
rmsChoice.toolTip = "Select the random map script to run";
|
||||
function loadScriptChoices()
|
||||
{
|
||||
// Reload RMS data
|
||||
Atlas.State.scriptNames = [];
|
||||
Atlas.State.scriptData = [];
|
||||
|
||||
// Get array of RMS data
|
||||
var rawData = Atlas.Message.GetRMSData().data;
|
||||
for (var i = 0; i < rawData.length; ++i)
|
||||
{
|
||||
// Parse JSON strings to objects
|
||||
var data = JSON.parse(rawData[i]);
|
||||
if (data && data.settings)
|
||||
{
|
||||
Atlas.State.scriptData.push(data);
|
||||
Atlas.State.scriptNames.push(data.settings.Name);
|
||||
}
|
||||
}
|
||||
|
||||
// Add script names to choice control
|
||||
rmsChoice.clear();
|
||||
rmsChoice.append(Atlas.State.scriptNames);
|
||||
rmsChoice.selection = 0;
|
||||
}
|
||||
boxSizer.add(rmsChoice, 1, wxAlignment.CENTER_VERTICAL);
|
||||
boxSizer.add(5, 0);
|
||||
var rmsReload = new wxButton(rmsPanel, -1, 'R', wxDefaultPosition, new wxSize(20, -1));
|
||||
rmsReload.toolTip = 'Click to refresh random map list';
|
||||
rmsReload.onClicked = function()
|
||||
{
|
||||
loadScriptChoices();
|
||||
};
|
||||
boxSizer.add(rmsReload, 0, wxAlignment.CENTER_VERTICAL);
|
||||
rmsSizer.add(boxSizer, 0, wxStretch.EXPAND | wxDirection.ALL, 2);
|
||||
|
||||
boxSizer = new wxBoxSizer(wxOrientation.HORIZONTAL);
|
||||
boxSizer.add(new wxStaticText(rmsPanel, -1, 'Map size'), 0, wxAlignment.CENTER_VERTICAL);
|
||||
boxSizer.add(10, 0);
|
||||
// TODO: Get this data from single location (currently specified here, Atlas\lists.xml, and game setup)
|
||||
var sizeNames = ["Tiny", "Small", "Medium", "Normal", "Large", "Very Large", "Giant"];
|
||||
var sizeTiles = [128, 192, 256, 320, 384, 448, 512];
|
||||
var sizeChoice = new wxChoice(rmsPanel, -1, wxDefaultPosition, wxDefaultSize, sizeNames);
|
||||
var numChoices = sizeNames.length;
|
||||
sizeChoice.toolTip = 'Select the desired map size\n'+sizeNames[0]+' = '+sizeTiles[0]+' patches, '+sizeNames[numChoices-1]+' = '+sizeTiles[numChoices-1]+' patches';
|
||||
sizeChoice.selection = 0;
|
||||
boxSizer.add(sizeChoice, 1);
|
||||
rmsSizer.add(boxSizer, 0, wxStretch.EXPAND | wxDirection.ALL, 2);
|
||||
|
||||
boxSizer = new wxBoxSizer(wxOrientation.HORIZONTAL);
|
||||
var generateBtn = new wxButton(rmsPanel, -1, 'Generate');
|
||||
generateBtn.toolTip = 'Generate random map using selected script';
|
||||
generateBtn.onClicked = function ()
|
||||
{
|
||||
var selection = rmsChoice.selection;
|
||||
if (selection != -1)
|
||||
{
|
||||
var RMSData = Atlas.State.scriptData[selection].settings;
|
||||
if (RMSData)
|
||||
{
|
||||
if (useRandomCtrl.value)
|
||||
{ // Generate random seed
|
||||
generateRandomSeed();
|
||||
}
|
||||
|
||||
// Copy RMS data to map settings
|
||||
for (var prop in RMSData)
|
||||
{
|
||||
Atlas.State.mapSettings.settings[prop] = RMSData[prop];
|
||||
}
|
||||
|
||||
// Complete map settings
|
||||
Atlas.State.mapSettings.settings.Seed = Atlas.State.Seed ? Atlas.State.Seed : 0;
|
||||
Atlas.State.mapSettings.settings.Size = sizeTiles[sizeChoice.selection];
|
||||
|
||||
// TODO: Would be nice to have some sort of busy notification here
|
||||
|
||||
// Generate map
|
||||
var ret = Atlas.Message.GenerateMap(RMSData.Script, JSON.stringify(Atlas.State.mapSettings.settings));
|
||||
|
||||
// Check for error
|
||||
if (ret.status < 0)
|
||||
{
|
||||
wxMessageBox("Random map script '"+RMSData.Script+"' failed. Loading blank map.");
|
||||
|
||||
Atlas.Message.LoadMap("_default");
|
||||
}
|
||||
Atlas.State.mapSettings.notifyObservers();
|
||||
}
|
||||
}
|
||||
};
|
||||
boxSizer.add(generateBtn, 0);
|
||||
boxSizer.add(5, 0);
|
||||
boxSizer.add(new wxStaticText(rmsPanel, -1, 'Random seed'), 0, wxAlignment.CENTER_VERTICAL);
|
||||
boxSizer.add(5, 0);
|
||||
var useRandomCtrl = new wxCheckBox(rmsPanel, -1, '');
|
||||
useRandomCtrl.toolTip = 'Always generate a new random seed';
|
||||
useRandomCtrl.value = true;
|
||||
boxSizer.add(useRandomCtrl, 0, wxAlignment.CENTER_VERTICAL);
|
||||
rmsSizer.add(boxSizer, 0, wxStretch.EXPAND | wxDirection.ALL, 2);
|
||||
|
||||
boxSizer = new wxBoxSizer(wxOrientation.HORIZONTAL);
|
||||
boxSizer.add(new wxStaticText(rmsPanel, -1, 'Seed'), 0, wxAlignment.CENTER_VERTICAL);
|
||||
boxSizer.add(10, 0);
|
||||
var seedCtrl = new wxTextCtrl(rmsPanel, -1, '', wxDefaultPosition, new wxSize(60,-1));
|
||||
seedCtrl.toolTip = 'Enter a numeric seed value here';
|
||||
seedCtrl.onText = function()
|
||||
{
|
||||
var num = parseInt(this.value, 10);
|
||||
if (!isNaN(num))
|
||||
{
|
||||
Atlas.State.Seed = num;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Can allow text by hashing it into a seed value - for fun?
|
||||
}
|
||||
};
|
||||
boxSizer.add(seedCtrl, 1);
|
||||
function generateRandomSeed()
|
||||
{
|
||||
seedCtrl.value = Math.floor(Math.random() * 2147483648)+ 1;
|
||||
}
|
||||
rmsSizer.add(boxSizer, 0, wxStretch.EXPAND | wxDirection.ALL, 2);
|
||||
|
||||
// TODO: Possibly have controls for base height + terrain to override RMS
|
||||
|
||||
rmsPanel.sizer = rmsSizer;
|
||||
window.sizer.add(rmsPanel, 0, wxStretch.EXPAND | wxDirection.LEFT|wxDirection.RIGHT, 2);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Simulation controls
|
||||
setupSimTest(window, rmsPanel);
|
||||
|
||||
|
||||
// Initial seed
|
||||
seedCtrl.value = 0;
|
||||
|
||||
g_observer = function()
|
||||
{
|
||||
if (!g_externalNotify)
|
||||
{
|
||||
// We have to do these steps here, because the simulation is not
|
||||
// initialized when this script is first loaded
|
||||
|
||||
// If we don't have civ data, load those
|
||||
if (!Atlas.State.CivData)
|
||||
{
|
||||
loadCivData();
|
||||
}
|
||||
|
||||
// If we don't have default player data, load those
|
||||
if (!Atlas.State.PlayerDefaults)
|
||||
{
|
||||
loadPlayerDefaults();
|
||||
}
|
||||
|
||||
// If we don't have RMS data yet, load those
|
||||
if (!Atlas.State.scriptData)
|
||||
{
|
||||
loadScriptChoices();
|
||||
}
|
||||
|
||||
// Load map settings from engine
|
||||
getMapSettings();
|
||||
|
||||
// Update UI controls
|
||||
updateMapName();
|
||||
updateMapDesc();
|
||||
updateRevealMap();
|
||||
updateGameType();
|
||||
updateNumPlayers();
|
||||
updateKeywords();
|
||||
}
|
||||
}
|
||||
|
||||
// Set up observers (so that this script can be notified when map data is loaded)
|
||||
makeObservable(Atlas.State.mapSettings);
|
||||
|
||||
Atlas.State.mapSettings.registerObserver(g_observer);
|
||||
}
|
||||
|
||||
function deinit()
|
||||
{
|
||||
Atlas.State.mapSettings.unregisterObserver(g_observer);
|
||||
}
|
@ -1,353 +0,0 @@
|
||||
function setObjectFilter(objectList, objects, type)
|
||||
{
|
||||
objectList.freeze();
|
||||
objectList.clear();
|
||||
var ids = [];
|
||||
for each (var object in objects) {
|
||||
if (object.type == type) {
|
||||
ids.push(object.id);
|
||||
objectList.append(object.name);
|
||||
}
|
||||
}
|
||||
objectList.objectIDs = ids;
|
||||
objectList.thaw();
|
||||
}
|
||||
|
||||
var actorViewer = {
|
||||
active: false,
|
||||
distance: 20,
|
||||
angle: 0,
|
||||
elevation: Math.PI / 6,
|
||||
actor: "actor|structures/fndn_1x1.xml",
|
||||
animation: "idle",
|
||||
// Animation playback speed
|
||||
speed: 0,
|
||||
// List of controls which should be hidden, and only shown when the Actor Viewer is active
|
||||
controls: []
|
||||
};
|
||||
|
||||
actorViewer.toggle = function () {
|
||||
if (this.active) {
|
||||
// TODO: maybe this should switch back to whatever was selected before,
|
||||
// not necessarily PlaceObject
|
||||
Atlas.SetCurrentToolWith('PlaceObject', this.actor);
|
||||
} else {
|
||||
Atlas.SetCurrentToolWithVal('ScriptedTool', this);
|
||||
}
|
||||
};
|
||||
|
||||
actorViewer.postToGame = function () {
|
||||
Atlas.Message.SetActorViewer(this.actor, this.animation, this.speed, false);
|
||||
};
|
||||
|
||||
actorViewer.postLookAt = function () {
|
||||
var offset = 0.3; // slight fudge so we turn nicely when going over the top of the unit
|
||||
var pos = {
|
||||
x: this.distance*Math.cos(this.elevation)*Math.sin(this.angle) + offset*Math.cos(this.angle),
|
||||
y: this.distance*Math.sin(this.elevation),
|
||||
z: this.distance*Math.cos(this.elevation)*Math.cos(this.angle) - offset*Math.sin(this.angle)
|
||||
};
|
||||
Atlas.Message.LookAt(Atlas.RenderView.ACTOR, pos, {x:0, y:0, z:0});
|
||||
};
|
||||
|
||||
actorViewer.setActor = function (actor) {
|
||||
this.actor = actor;
|
||||
if (this.active) {
|
||||
this.postToGame();
|
||||
Atlas.State.objectSettings.onSelectionChange();
|
||||
}
|
||||
}
|
||||
|
||||
actorViewer.onEnable = function () {
|
||||
this.active = true;
|
||||
this.button.label = this.buttonTextActive;
|
||||
for each (ctrl in actorViewer.controls)
|
||||
ctrl.show(true);
|
||||
this.postToGame();
|
||||
Atlas.State.objectSettings.view = Atlas.RenderView.ACTOR;
|
||||
Atlas.State.objectSettings.selectedObjects = [0];
|
||||
Atlas.State.objectSettings.onSelectionChange(); // (must come after postToGame)
|
||||
this.postLookAt();
|
||||
Atlas.Message.RenderEnable(Atlas.RenderView.ACTOR);
|
||||
}
|
||||
|
||||
actorViewer.onDisable = function () {
|
||||
this.active = false;
|
||||
this.button.label = this.buttonTextInactive;
|
||||
for each (ctrl in actorViewer.controls)
|
||||
ctrl.show(false);
|
||||
Atlas.State.objectSettings.view = Atlas.RenderView.GAME;
|
||||
Atlas.State.objectSettings.selectedObjects = [];
|
||||
Atlas.State.objectSettings.onSelectionChange();
|
||||
Atlas.Message.RenderEnable(Atlas.RenderView.GAME);
|
||||
}
|
||||
|
||||
actorViewer.onKey = function (evt, type) {
|
||||
var code0 = '0'.charCodeAt(0);
|
||||
var code9 = '9'.charCodeAt(0);
|
||||
if (type == 'down' && evt.keyCode >= code0 && evt.keyCode <= code9) {
|
||||
// (TODO: this should probably be 'char' not 'down'; but we don't get
|
||||
// 'char' unless we return false from this function, in which case the
|
||||
// scenario editor intercepts some other keys for itself)
|
||||
Atlas.State.objectSettings.playerID = evt.keyCode - code0;
|
||||
Atlas.State.objectSettings.notifyObservers();
|
||||
}
|
||||
|
||||
// Prevent keys from passing through to the scenario editor
|
||||
return true;
|
||||
}
|
||||
|
||||
actorViewer.onMouse = function (evt) {
|
||||
var cameraChanged = false;
|
||||
|
||||
var speedModifier = this.getSpeedModifier();
|
||||
|
||||
if (evt.wheelRotation) {
|
||||
var speed = -1 * speedModifier;
|
||||
this.distance += evt.wheelRotation * speed / evt.wheelDelta;
|
||||
cameraChanged = true;
|
||||
}
|
||||
|
||||
if (evt.leftDown || evt.rightDown) {
|
||||
this.mouseLastX = evt.x;
|
||||
this.mouseLastY = evt.y;
|
||||
this.mouseLastValid = true;
|
||||
} else if (evt.dragging && this.mouseLastValid && (evt.leftIsDown || evt.rightIsDown)) {
|
||||
var dx = evt.x - this.mouseLastX;
|
||||
var dy = evt.y - this.mouseLastY;
|
||||
this.mouseLastX = evt.x;
|
||||
this.mouseLastY = evt.y;
|
||||
this.angle += dx * Math.PI/256 * speedModifier;
|
||||
if (evt.leftIsDown)
|
||||
this.distance += (dy / 8) * speedModifier;
|
||||
else // evt.rightIsDown
|
||||
this.elevation += (dy * Math.PI/256) * speedModifier;
|
||||
cameraChanged = true;
|
||||
} else if ((evt.leftUp || evt.rightUp) && ! (evt.leftDown || evt.rightDown)) {
|
||||
// In some situations (e.g. double-clicking the title bar to
|
||||
// maximise the window) we get a dragging event without the matching
|
||||
// buttondown; so disallow dragging when all buttons were released since
|
||||
// the last buttondown.
|
||||
// (TODO: does this problem affect the scenario editor too?)
|
||||
this.mouseLastValid = false;
|
||||
}
|
||||
|
||||
if (cameraChanged) {
|
||||
this.distance = Math.max(this.distance, 1/64); // don't let people fly through the origin
|
||||
this.postLookAt();
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
actorViewer.getSpeedModifier = function () { // TODO: this should be shared with the rest of the application
|
||||
if (wxGetKeyState(wxKeyCode.SHIFT) && wxGetKeyState(wxKeyCode.CONTROL))
|
||||
return 1/64;
|
||||
else if (wxGetKeyState(wxKeyCode.CONTROL))
|
||||
return 1/4;
|
||||
else if (wxGetKeyState(wxKeyCode.SHIFT))
|
||||
return 4;
|
||||
else
|
||||
return 1;
|
||||
};
|
||||
|
||||
|
||||
var g_observer;
|
||||
|
||||
function init(window, bottomWindow)
|
||||
{
|
||||
window.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
|
||||
|
||||
var objects = Atlas.Message.GetObjectsList().objects;
|
||||
|
||||
var objectList = new wxListBox(window, -1, wxDefaultPosition, wxDefaultSize, [],
|
||||
wxListBox.SINGLE | wxListBox.HSCROLL);
|
||||
var objectType = 0;
|
||||
objectList.onListBox = function (evt) {
|
||||
if (evt.selection == -1)
|
||||
return;
|
||||
var id = objectList.objectIDs[evt.selection];
|
||||
|
||||
actorViewer.setActor(id);
|
||||
if (! actorViewer.active)
|
||||
Atlas.SetCurrentToolWith('PlaceObject', id);
|
||||
};
|
||||
setObjectFilter(objectList, objects, objectType);
|
||||
|
||||
var groupSelector = new wxChoice(window, -1, wxDefaultPosition, wxDefaultSize,
|
||||
["Entities", "Actors (all)"]
|
||||
);
|
||||
groupSelector.onChoice = function (evt) {
|
||||
objectType = evt.selection;
|
||||
setObjectFilter(objectList, objects, objectType);
|
||||
};
|
||||
|
||||
window.sizer.add(groupSelector, 0, wxStretch.EXPAND);
|
||||
window.sizer.add(objectList, 1, wxStretch.EXPAND);
|
||||
|
||||
|
||||
var viewerButton = new wxButton(window, -1, "Switch to Actor Viewer");
|
||||
actorViewer.button = viewerButton;
|
||||
actorViewer.buttonTextInactive = "Switch to Actor Viewer";
|
||||
actorViewer.buttonTextActive = "Switch to game view";
|
||||
viewerButton.onClicked = function () { actorViewer.toggle(); }
|
||||
window.sizer.add(viewerButton, 0, wxStretch.EXPAND);
|
||||
|
||||
|
||||
|
||||
// Actor viewer settings:
|
||||
var displaySettingsBoxBox = new wxStaticBox(bottomWindow, -1, "Display settings");
|
||||
actorViewer.controls.push(displaySettingsBoxBox);
|
||||
var displaySettingsBox = new wxStaticBoxSizer(displaySettingsBoxBox, wxOrientation.VERTICAL);
|
||||
displaySettingsBox.minSize = new wxSize(140, -1);
|
||||
var displaySettings = [
|
||||
["Wireframe", "Toggle wireframe / solid rendering", "wireframe", false],
|
||||
["Move", "Toggle movement along ground when playing walk/run animations", "walk", false],
|
||||
["Ground", "Toggle the ground plane", "ground", true],
|
||||
["Shadows", "Toggle shadow rendering", "shadows", true],
|
||||
["Poly count", "Toggle polygon-count statistics - turn off ground and shadows for more useful data", "stats", false]
|
||||
];
|
||||
// NOTE: there's also a background colour setting, which isn't exposed
|
||||
// by this UI because I don't know if it's worth the effort
|
||||
for each (var setting in displaySettings) {
|
||||
var button = new wxButton(bottomWindow, -1, setting[0]);
|
||||
actorViewer.controls.push(button);
|
||||
button.toolTip = setting[1];
|
||||
// Set the default value
|
||||
Atlas.Message.SetViewParamB(Atlas.RenderView.ACTOR, setting[2], setting[3]);
|
||||
// Toggle the value on clicks
|
||||
(function (s) { // local scope for closure
|
||||
button.onClicked = function () {
|
||||
s[3] = !s[3];
|
||||
Atlas.Message.SetViewParamB(Atlas.RenderView.ACTOR, s[2], s[3]);
|
||||
};
|
||||
})(setting);
|
||||
displaySettingsBox.add(button, 0, wxStretch.EXPAND);
|
||||
}
|
||||
// TODO: It might be nice to add an "edit this actor" button
|
||||
// in the actor viewer (when we have working actor hotloading)
|
||||
|
||||
|
||||
var playerSelector = new wxChoice(bottomWindow, -1, wxDefaultPosition, wxDefaultSize,
|
||||
["Gaia", "Player 1", "Player 2", "Player 3", "Player 4", "Player 5", "Player 6", "Player 7", "Player 8"]
|
||||
);
|
||||
playerSelector.selection = Atlas.State.objectSettings.playerID;
|
||||
playerSelector.onChoice = function (evt) {
|
||||
Atlas.State.objectSettings.playerID = evt.selection;
|
||||
Atlas.State.objectSettings.notifyObservers();
|
||||
};
|
||||
function updatePlayerSelector() {
|
||||
playerSelector.selection = Atlas.State.objectSettings.playerID;
|
||||
}
|
||||
|
||||
var animationBoxBox = new wxStaticBox(bottomWindow, -1, "Animation");
|
||||
actorViewer.controls.push(animationBoxBox);
|
||||
var animationBox = new wxStaticBoxSizer(animationBoxBox, wxOrientation.VERTICAL);
|
||||
var animationSelector = new wxChoice(bottomWindow, -1, wxDefaultPosition, wxDefaultSize,
|
||||
[ "idle", "walk", "run", "melee", "death", "build",
|
||||
"gather_fruit", "gather_grain", "gather_meat",
|
||||
"gather_tree", "gather_rock", "gather_ore", "gather_ruins", "gather_treasure" ] // TODO: this list should come from the actor
|
||||
);
|
||||
animationSelector.stringSelection = "idle";
|
||||
actorViewer.controls.push(animationSelector);
|
||||
animationSelector.onChoice = function (evt) {
|
||||
actorViewer.animation = evt.string;
|
||||
actorViewer.postToGame();
|
||||
};
|
||||
var animationSpeedSizer = new wxBoxSizer(wxOrientation.HORIZONTAL);
|
||||
var speeds = [ ['Play', 1], ['Pause', 0], ['Slow', 0.1] ];
|
||||
for each (var speed in speeds) {
|
||||
var button = new wxButton(bottomWindow, -1, speed[0], wxDefaultPosition, new wxSize(50, -1));
|
||||
actorViewer.controls.push(button);
|
||||
(function (s) { // local scope for closure
|
||||
button.onClicked = function () {
|
||||
actorViewer.speed = s;
|
||||
actorViewer.postToGame();
|
||||
};
|
||||
})(speed[1]);
|
||||
animationSpeedSizer.add(button);
|
||||
}
|
||||
animationBox.add(animationSelector, 0, wxStretch.EXPAND);
|
||||
animationBox.add(animationSpeedSizer, 0, wxStretch.EXPAND);
|
||||
|
||||
|
||||
var animationSizer = new wxBoxSizer(wxOrientation.VERTICAL);
|
||||
animationSizer.minSize = new wxSize(160, -1);
|
||||
animationSizer.add(playerSelector, 0, wxStretch.EXPAND);
|
||||
animationSizer.add(animationBox, 0, wxStretch.EXPAND);
|
||||
|
||||
|
||||
for each (ctrl in actorViewer.controls)
|
||||
ctrl.show(false);
|
||||
|
||||
|
||||
var variationControl = new wxScrolledWindow(bottomWindow, -1);
|
||||
variationControl.setScrollRate(0, 5);
|
||||
variationControl.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
|
||||
var variationControlBox = new wxStaticBoxSizer(new wxStaticBox(bottomWindow, -1, "Actor Variation"), wxOrientation.VERTICAL);
|
||||
variationControl.sizer.minSize = new wxSize(160, -1);
|
||||
variationControlBox.add(variationControl, 1);
|
||||
|
||||
function onVariationSelect() {
|
||||
// It's possible for a variant name to appear in multiple groups.
|
||||
// If so, assume that all the names in each group are the same, so
|
||||
// we don't have to worry about some impossible combinations (e.g.
|
||||
// one group "a,b", a second "b,c", and a third "c,a", where's there's
|
||||
// no set of selections that matches one (and only one) of each group).
|
||||
//
|
||||
// So... When a combo box is changed from 'a' to 'b', add 'b' to the new
|
||||
// selections and make sure any other combo boxes containing both 'a' and
|
||||
// 'b' no longer contain 'a'.
|
||||
|
||||
var sel = this.stringSelection;
|
||||
var selections = [ sel ];
|
||||
for each (var c in variationControl.children)
|
||||
if (c.findString(sel) == wxNOT_FOUND)
|
||||
selections.push(c.stringSelection);
|
||||
|
||||
Atlas.State.objectSettings.actorSelections = selections;
|
||||
Atlas.State.objectSettings.notifyObservers();
|
||||
}
|
||||
|
||||
function updateVariationControl() {
|
||||
variationControl.freeze();
|
||||
variationControl.sizer.clear(true);
|
||||
var settings = Atlas.State.objectSettings;
|
||||
var variation = settings.getActorVariation();
|
||||
for (var i = 0; i < settings.variantgroups.length; ++i) {
|
||||
var choice = new wxChoice(variationControl, -1, wxDefaultPosition, new wxSize(80, -1),
|
||||
settings.variantgroups[i]);
|
||||
choice.onChoice = onVariationSelect;
|
||||
choice.stringSelection = variation[i];
|
||||
variationControl.sizer.add(choice, 0, wxStretch.EXPAND);
|
||||
}
|
||||
// TODO: this sizer stuff is a bit dodgy - it often doesn't quite
|
||||
// update the sizes and scrollbars at the right points
|
||||
variationControl.thaw();
|
||||
variationControlBox.layout();
|
||||
variationControl.sizer.layout();
|
||||
bottomWindow.sizer.layout();
|
||||
}
|
||||
|
||||
|
||||
bottomWindow.sizer = new wxBoxSizer(wxOrientation.HORIZONTAL);
|
||||
bottomWindow.sizer.add(displaySettingsBox);
|
||||
bottomWindow.sizer.add(animationSizer);
|
||||
bottomWindow.sizer.add(variationControlBox, 0, wxStretch.EXPAND);
|
||||
|
||||
|
||||
g_observer = function() {
|
||||
updatePlayerSelector();
|
||||
updateVariationControl();
|
||||
};
|
||||
Atlas.State.objectSettings.registerObserver(g_observer);
|
||||
|
||||
// Initialise the controls
|
||||
g_observer();
|
||||
}
|
||||
|
||||
function deinit()
|
||||
{
|
||||
Atlas.State.objectSettings.unregisterObserver(g_observer);
|
||||
}
|
||||
|
@ -1,192 +0,0 @@
|
||||
var brushShapes = {
|
||||
'circle': {
|
||||
width: function (size) { return size },
|
||||
height: function (size) { return size },
|
||||
data: function (size) {
|
||||
var data = [];
|
||||
// All calculations are done in units of half-tiles, since that
|
||||
// is the required precision
|
||||
var mid_x = size-1;
|
||||
var mid_y = size-1;
|
||||
var scale = 1 / (Math.sqrt(2) - 1);
|
||||
for (var y = 0; y < size; ++y)
|
||||
{
|
||||
for (var x = 0; x < size; ++x)
|
||||
{
|
||||
var dist_sq = // scaled to 0 in centre, 1 on edge
|
||||
((2*x - mid_x)*(2*x - mid_x) +
|
||||
(2*y - mid_y)*(2*y - mid_y)) / (size*size);
|
||||
if (dist_sq <= 1)
|
||||
data.push((Math.sqrt(2 - dist_sq) - 1) * scale);
|
||||
else
|
||||
data.push(0);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
},
|
||||
|
||||
'square': {
|
||||
width: function (size) { return size },
|
||||
height: function (size) { return size },
|
||||
data: function (size) {
|
||||
var data = [];
|
||||
for (var i = 0; i < size*size; ++i)
|
||||
data.push(1);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var brush = {
|
||||
shape: brushShapes['circle'],
|
||||
size: 4,
|
||||
strength: 1.0,
|
||||
active: false,
|
||||
send: function () {
|
||||
Atlas.Message.Brush(
|
||||
this.shape.width(this.size),
|
||||
this.shape.height(this.size),
|
||||
this.shape.data(this.size)
|
||||
);
|
||||
// TODO: rather than this hack to make things interact correctly with C++ tools,
|
||||
// implement the tools in JS and do something better
|
||||
Atlas.SetBrushStrength(this.strength);
|
||||
}
|
||||
};
|
||||
|
||||
function init(window, bottomWindow)
|
||||
{
|
||||
window.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
|
||||
|
||||
var tools = [
|
||||
{ label: 'Modify', name: 'AlterElevation' },
|
||||
{ label: 'Smooth', name: 'SmoothElevation' },
|
||||
{ label: 'Flatten', name: 'FlattenElevation' },
|
||||
{ label: 'Paint', name: 'PaintTerrain' },
|
||||
];
|
||||
var selectedTool = null; // null if none selected, else an element of 'tools'
|
||||
|
||||
var toolSizer = new wxStaticBoxSizer(new wxStaticBox(window, -1, 'Elevation tools'), wxOrientation.HORIZONTAL);
|
||||
window.sizer.add(toolSizer, 0, wxStretch.EXPAND);
|
||||
for each (var tool in tools)
|
||||
{
|
||||
var button = new wxButton(window, -1, tool.label);
|
||||
toolSizer.add(button, 1);
|
||||
tool.button = button;
|
||||
|
||||
// Explicitly set the background to the default colour, so that the button
|
||||
// is always owner-drawn (by the wxButton code), rather than initially using the
|
||||
// native (standard colour) button appearance then changing inconsistently later.
|
||||
button.backgroundColour = wxSystemSettings.getColour(wxSystemSettings.COLOUR_BTNFACE);
|
||||
|
||||
(function(tool) { // (local scope)
|
||||
button.onClicked = function () {
|
||||
if (selectedTool == tool)
|
||||
{
|
||||
// Clicking on one tool twice should disable it
|
||||
selectedTool = null;
|
||||
this.backgroundColour = wxSystemSettings.getColour(wxSystemSettings.COLOUR_BTNFACE);
|
||||
Atlas.SetCurrentTool('');
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disable the old tool
|
||||
if (selectedTool)
|
||||
selectedTool.button.backgroundColour = wxSystemSettings.getColour(wxSystemSettings.COLOUR_BTNFACE);
|
||||
// Enable the new one
|
||||
selectedTool = tool;
|
||||
this.backgroundColour = new wxColour(0xEE, 0xCC, 0x55);
|
||||
Atlas.SetCurrentTool(tool.name);
|
||||
brush.send();
|
||||
}
|
||||
};
|
||||
})(tool);
|
||||
// TODO: Need to make this interact properly with Tools.cpp/RegisterToolButton so all the buttons are in sync
|
||||
}
|
||||
|
||||
var brushSizer = new wxStaticBoxSizer(new wxStaticBox(window, -1, 'Brush'), wxOrientation.VERTICAL);
|
||||
window.sizer.add(brushSizer);
|
||||
|
||||
var shapes = [
|
||||
[ 'Circle', brushShapes['circle'] ],
|
||||
[ 'Square', brushShapes['square'] ]
|
||||
];
|
||||
var shapeNames = [];
|
||||
for each (var s in shapes) shapeNames.push(s[0]);
|
||||
var shapeBox = new wxRadioBox(window, -1, 'Shape', wxDefaultPosition, wxDefaultSize, shapeNames, 0, wxRadioBox.SPECIFY_ROWS);
|
||||
brushSizer.add(shapeBox);
|
||||
shapeBox.onRadioBox = function(evt)
|
||||
{
|
||||
brush.shape = shapes[evt.integer][1];
|
||||
brush.send();
|
||||
};
|
||||
|
||||
var brushSettingsSizer = new wxFlexGridSizer(2);
|
||||
|
||||
brushSizer.add(brushSettingsSizer);
|
||||
brushSettingsSizer.add(new wxStaticText(window, -1, 'Size'), 0, wxAlignment.RIGHT);
|
||||
var sizeSpinner = new wxSpinCtrl(window, -1, 4, wxDefaultPosition, wxDefaultSize, wxSpinCtrl.ARROW_KEYS, 1, 100);
|
||||
brushSettingsSizer.add(sizeSpinner);
|
||||
sizeSpinner.onSpinCtrl = function(evt)
|
||||
{
|
||||
brush.size = evt.position;
|
||||
brush.send();
|
||||
};
|
||||
|
||||
brushSettingsSizer.add(new wxStaticText(window, -1, 'Strength'), wxAlignment.RIGHT);
|
||||
var strengthSpinner = new wxSpinCtrl(window, -1, 10, wxDefaultPosition, wxDefaultSize, wxSpinCtrl.ARROW_KEYS, 1, 100);
|
||||
brushSettingsSizer.add(strengthSpinner);
|
||||
strengthSpinner.onSpinCtrl = function(evt)
|
||||
{
|
||||
brush.strength = evt.position / 10;
|
||||
brush.send();
|
||||
};
|
||||
|
||||
|
||||
|
||||
var visualiseSizer = new wxStaticBoxSizer(new wxStaticBox(window, -1, 'Visualise'), wxOrientation.VERTICAL);
|
||||
window.sizer.add(visualiseSizer);
|
||||
var visualiseSettingsSizer = new wxFlexGridSizer(2);
|
||||
visualiseSizer.add(visualiseSettingsSizer);
|
||||
|
||||
visualiseSettingsSizer.add(new wxStaticText(window, -1, 'Passability'), 0, wxAlignment.RIGHT);
|
||||
var passabilityClasses = Atlas.Message.GetTerrainPassabilityClasses().classNames;
|
||||
var passabilitySelector = new wxChoice(window, -1, wxDefaultPosition, wxDefaultSize,
|
||||
["(none)"].concat(passabilityClasses)
|
||||
);
|
||||
passabilitySelector.selection = 0;
|
||||
visualiseSettingsSizer.add(passabilitySelector);
|
||||
passabilitySelector.onChoice = function (evt) {
|
||||
if (evt.selection == 0)
|
||||
Atlas.Message.SetViewParamS(Atlas.RenderView.GAME, "passability", "");
|
||||
else
|
||||
Atlas.Message.SetViewParamS(Atlas.RenderView.GAME, "passability", evt.string);
|
||||
};
|
||||
|
||||
visualiseSettingsSizer.add(new wxStaticText(window, -1, 'Priorities'), 0, wxAlignment.RIGHT);
|
||||
var priorityCheckbox = new wxCheckBox(window, -1, "");
|
||||
visualiseSettingsSizer.add(priorityCheckbox);
|
||||
priorityCheckbox.onCheckBox = function (evt) {
|
||||
Atlas.Message.SetViewParamB(Atlas.RenderView.GAME, "priorities", evt.checked);
|
||||
};
|
||||
|
||||
|
||||
var terrainGroups = Atlas.Message.GetTerrainGroups();
|
||||
var nb = new wxNotebook(bottomWindow, -1);
|
||||
bottomWindow.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
|
||||
bottomWindow.sizer.add(nb, 1, wxStretch.EXPAND);
|
||||
|
||||
var pages = [];
|
||||
nb.onPageChanged = function (evt) {
|
||||
pages[evt.selection].display()
|
||||
evt.skip = true;
|
||||
}
|
||||
for each (var groupName in terrainGroups.groupNames)
|
||||
{
|
||||
var panel = new wxPanel(nb, -1);
|
||||
var page = new global.TerrainPreviewPage(panel, groupName);
|
||||
pages.push(page);
|
||||
nb.addPage(panel, groupName); // TODO: use Titlecase letters
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
|
||||
function init(window)
|
||||
{
|
||||
var terrainGroups = Atlas.Message.GetTerrainGroups();
|
||||
var nb = new wxNotebook(window, -1);
|
||||
window.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
|
||||
window.sizer.add(nb, 1, wxStretch.EXPAND);
|
||||
|
||||
var pages = [];
|
||||
nb.onPageChanged = function (evt) {
|
||||
pages[evt.selection].display()
|
||||
evt.skip = true;
|
||||
}
|
||||
for each (var groupName in terrainGroups.groupNames)
|
||||
{
|
||||
var panel = new wxPanel(nb, -1);
|
||||
var page = new global.TerrainPreviewPage(panel, groupName);
|
||||
pages.push(page);
|
||||
nb.addPage(panel, groupName); // TODO: use Titlecase letters
|
||||
}
|
||||
}
|
@ -784,25 +784,6 @@ function setup_atlas_packages()
|
||||
},{ -- extra_params
|
||||
})
|
||||
|
||||
setup_atlas_package("wxJS", "lib",
|
||||
{ -- src
|
||||
"",
|
||||
"common",
|
||||
"ext",
|
||||
"gui",
|
||||
"gui/control",
|
||||
"gui/event",
|
||||
"gui/misc",
|
||||
"io",
|
||||
},{ -- include
|
||||
},{ -- extern_libs
|
||||
"spidermonkey",
|
||||
"wxwidgets"
|
||||
},{ -- extra_params
|
||||
pch = (not has_broken_pch),
|
||||
no_unused_warnings = 1, -- wxJS has far too many and we're never going to fix them, so just ignore them
|
||||
})
|
||||
|
||||
atlas_src = {
|
||||
"ActorEditor",
|
||||
"ColourTester",
|
||||
@ -834,7 +815,6 @@ function setup_atlas_packages()
|
||||
atlas_extra_links = {
|
||||
"AtlasObject",
|
||||
"AtlasScript",
|
||||
"wxJS",
|
||||
}
|
||||
if options["aoe3ed"] then
|
||||
tinsert(atlas_src, "ArchiveViewer")
|
||||
|
@ -31,16 +31,6 @@
|
||||
|
||||
#include "wx/wx.h"
|
||||
|
||||
#include "wxJS/common/main.h"
|
||||
#include "wxJS/ext/wxjs_ext.h"
|
||||
#include "wxJS/io/init.h"
|
||||
#include "wxJS/gui/init.h"
|
||||
#include "wxJS/gui/control/panel.h"
|
||||
#include "wxJS/gui/misc/bitmap.h"
|
||||
#include "wxJS/gui/event/jsevent.h"
|
||||
#include "wxJS/gui/event/key.h"
|
||||
#include "wxJS/gui/event/mouse.h"
|
||||
|
||||
#include "GameInterface/Shareable.h"
|
||||
#include "GameInterface/Messages.h"
|
||||
|
||||
@ -310,31 +300,6 @@ namespace
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// wxJS types:
|
||||
|
||||
template<> struct ToJSVal<wxKeyEvent>
|
||||
{
|
||||
static jsval Convert(JSContext* cx, const wxKeyEvent& val)
|
||||
{
|
||||
wxKeyEvent& evt = const_cast<wxKeyEvent&>(val); // ugly, but needed for wxJS
|
||||
wxjs::gui::PrivKeyEvent *jsEvent = new wxjs::gui::PrivKeyEvent(evt);
|
||||
jsEvent->SetScoop(false); // (wxJS will clone the event now, and not modify the const version)
|
||||
return wxjs::gui::KeyEvent::CreateObject(cx, jsEvent);
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct ToJSVal<wxMouseEvent>
|
||||
{
|
||||
static jsval Convert(JSContext* cx, const wxMouseEvent& val)
|
||||
{
|
||||
wxMouseEvent& evt = const_cast<wxMouseEvent&>(val); // see comments above for KeyEvent
|
||||
wxjs::gui::PrivMouseEvent *jsEvent = new wxjs::gui::PrivMouseEvent(evt);
|
||||
jsEvent->SetScoop(false);
|
||||
return wxjs::gui::MouseEvent::CreateObject(cx, jsEvent);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Compound types:
|
||||
|
||||
@ -360,114 +325,6 @@ namespace
|
||||
return ToJSVal<T>::Convert(cx, val._Unwrap());
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// AtlasMessage structures:
|
||||
|
||||
template<> struct FromJSVal<AtlasMessage::Position>
|
||||
{
|
||||
static bool Convert(JSContext* cx, jsval v, AtlasMessage::Position& out)
|
||||
{
|
||||
JSObject* obj;
|
||||
if (! JS_ValueToObject(cx, v, &obj) || obj == NULL)
|
||||
FAIL("Argument must be an object");
|
||||
jsval val;
|
||||
|
||||
float x, y, z;
|
||||
if (! JS_GetProperty(cx, obj, "x", &val))
|
||||
FAIL("Failed to get 'x'");
|
||||
if (! ScriptInterface::FromJSVal(cx, val, x))
|
||||
FAIL("Failed to convert 'x'");
|
||||
if (! JS_GetProperty(cx, obj, "y", &val))
|
||||
FAIL("Failed to get 'y'");
|
||||
if (! ScriptInterface::FromJSVal(cx, val, y))
|
||||
FAIL("Failed to convert 'y'");
|
||||
if (! JS_GetProperty(cx, obj, "z", &val))
|
||||
FAIL("Failed to get 'z'");
|
||||
if (! ScriptInterface::FromJSVal(cx, val, z))
|
||||
FAIL("Failed to convert 'z'");
|
||||
|
||||
out = AtlasMessage::Position(x, y, z);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct ToJSVal<AtlasMessage::sTerrainGroupPreview>
|
||||
{
|
||||
static jsval Convert(JSContext* cx, const AtlasMessage::sTerrainGroupPreview& val)
|
||||
{
|
||||
JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
|
||||
if (! obj) return JSVAL_VOID;
|
||||
|
||||
JS_DefineProperty(cx, obj, "name", ToJSVal<std::wstring>::Convert(cx, *val.name), NULL, NULL, JSPROP_ENUMERATE);
|
||||
|
||||
JS_DefineProperty(cx, obj, "loaded", ToJSVal<bool>::Convert(cx, val.loaded), NULL, NULL, JSPROP_ENUMERATE);
|
||||
|
||||
unsigned char* buf = (unsigned char*)(malloc(val.imageData.GetSize()));
|
||||
memcpy(buf, val.imageData.GetBuffer(), val.imageData.GetSize());
|
||||
jsval bmp = wxjs::gui::Bitmap::CreateObject(cx, new wxBitmap (wxImage(val.imageWidth, val.imageHeight, buf)));
|
||||
JS_DefineProperty(cx, obj, "imagedata", bmp, NULL, NULL, JSPROP_ENUMERATE);
|
||||
|
||||
return OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct ToJSVal<AtlasMessage::sObjectsListItem>
|
||||
{
|
||||
static jsval Convert(JSContext* cx, const AtlasMessage::sObjectsListItem& val)
|
||||
{
|
||||
JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
|
||||
if (! obj) return JSVAL_VOID;
|
||||
JS_DefineProperty(cx, obj, "id", ToJSVal<std::wstring>::Convert(cx, *val.id), NULL, NULL, JSPROP_ENUMERATE);
|
||||
JS_DefineProperty(cx, obj, "name", ToJSVal<std::wstring>::Convert(cx, *val.name), NULL, NULL, JSPROP_ENUMERATE);
|
||||
JS_DefineProperty(cx, obj, "type", ToJSVal<int>::Convert(cx, val.type), NULL, NULL, JSPROP_ENUMERATE);
|
||||
return OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct ToJSVal<AtlasMessage::sObjectSettings>
|
||||
{
|
||||
static jsval Convert(JSContext* cx, const AtlasMessage::sObjectSettings& val)
|
||||
{
|
||||
JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
|
||||
if (! obj) return JSVAL_VOID;
|
||||
JS_DefineProperty(cx, obj, "player", ToJSVal<size_t>::Convert(cx, val.player), NULL, NULL, JSPROP_ENUMERATE);
|
||||
JS_DefineProperty(cx, obj, "selections", ToJSVal<std::vector<std::wstring> >::Convert(cx, *val.selections), NULL, NULL, JSPROP_ENUMERATE);
|
||||
JS_DefineProperty(cx, obj, "variantgroups", ToJSVal<std::vector<std::vector<std::wstring> > >::Convert(cx, *val.variantGroups), NULL, NULL, JSPROP_ENUMERATE);
|
||||
return OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct FromJSVal<AtlasMessage::sObjectSettings>
|
||||
{
|
||||
static bool Convert(JSContext* cx, jsval v, AtlasMessage::sObjectSettings& out)
|
||||
{
|
||||
JSObject* obj;
|
||||
if (! JS_ValueToObject(cx, v, &obj) || obj == NULL)
|
||||
FAIL("Argument must be an object");
|
||||
jsval val;
|
||||
|
||||
int player;
|
||||
if (! JS_GetProperty(cx, obj, "player", &val))
|
||||
FAIL("Failed to get 'player'");
|
||||
if (! ScriptInterface::FromJSVal(cx, val, player))
|
||||
FAIL("Failed to convert 'player'");
|
||||
out.player = player;
|
||||
|
||||
std::vector<std::wstring> selections;
|
||||
if (! JS_GetProperty(cx, obj, "selections", &val))
|
||||
FAIL("Failed to get 'selections'");
|
||||
if (! ScriptInterface::FromJSVal(cx, val, selections))
|
||||
FAIL("Failed to convert 'selections'");
|
||||
out.selections = selections;
|
||||
|
||||
// variantgroups is only used in engine-to-editor, so we don't
|
||||
// bother converting it here
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename T> bool ScriptInterface::FromJSVal(JSContext* cx, jsval v, T& out)
|
||||
@ -616,11 +473,6 @@ AtlasScriptInterface_impl::AtlasScriptInterface_impl()
|
||||
|
||||
JS_DefineProperty(m_cx, m_glob, "global", OBJECT_TO_JSVAL(m_glob), NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);
|
||||
|
||||
wxjs::gui::InitClass(m_cx, m_glob);
|
||||
wxjs::io::InitClass(m_cx, m_glob);
|
||||
wxjs::ext::InitClass(m_cx, m_glob);
|
||||
wxjs::ext::InitObject(m_cx, m_glob);
|
||||
|
||||
JS_DefineFunction(m_cx, m_glob, "print", ::print, 0, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);
|
||||
|
||||
m_atlas = JS_DefineObject(m_cx, m_glob, "Atlas", NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);
|
||||
@ -765,51 +617,6 @@ void ScriptInterface::LoadScript(const wxString& filename, const wxString& code)
|
||||
m->LoadScript(m->m_cx, reinterpret_cast<jschar*>(codeUTF16.data()), (uintN)(codeLength/2), filename.ToAscii(), &rval);
|
||||
}
|
||||
|
||||
wxPanel* ScriptInterface::LoadScriptAsPanel(const wxString& name, wxWindow* parent)
|
||||
{
|
||||
wxPanel* panel = new wxPanel(parent, -1);
|
||||
JSObject* jsWindow = JSVAL_TO_OBJECT(wxjs::gui::Panel::CreateObject(m->m_cx, panel));
|
||||
panel->SetClientObject(new wxjs::JavaScriptClientData(m->m_cx, jsWindow, true, false));
|
||||
|
||||
jsval jsName = ToJSVal(m->m_cx, name);
|
||||
|
||||
const uintN argc = 2;
|
||||
jsval argv[argc] = { jsName, OBJECT_TO_JSVAL(jsWindow) };
|
||||
|
||||
jsval rval;
|
||||
JS_CallFunctionName(m->m_cx, m->m_glob, "loadScript", argc, argv, &rval); // TODO: error checking
|
||||
return panel;
|
||||
}
|
||||
|
||||
// TODO: this is an ugly function to provide
|
||||
std::pair<wxPanel*, wxPanel*> ScriptInterface::LoadScriptAsSidebar(const wxString& name, wxWindow* side, wxWindow* bottom)
|
||||
{
|
||||
wxPanel* sidePanel = new wxPanel(side, -1);
|
||||
JSObject* jsSideWindow = JSVAL_TO_OBJECT(wxjs::gui::Panel::CreateObject(m->m_cx, sidePanel));
|
||||
sidePanel->SetClientObject(new wxjs::JavaScriptClientData(m->m_cx, jsSideWindow, true, false));
|
||||
|
||||
wxPanel* bottomPanel = new wxPanel(bottom, -1);
|
||||
JSObject* jsBottomWindow = JSVAL_TO_OBJECT(wxjs::gui::Panel::CreateObject(m->m_cx, bottomPanel));
|
||||
bottomPanel->SetClientObject(new wxjs::JavaScriptClientData(m->m_cx, jsBottomWindow, true, false));
|
||||
|
||||
jsval jsName = ToJSVal(m->m_cx, name);
|
||||
|
||||
const uintN argc = 3;
|
||||
jsval argv[argc] = { jsName, OBJECT_TO_JSVAL(jsSideWindow), OBJECT_TO_JSVAL(jsBottomWindow) };
|
||||
|
||||
jsval rval;
|
||||
JS_CallFunctionName(m->m_cx, m->m_glob, "loadScript", argc, argv, &rval); // TODO: error checking
|
||||
|
||||
// TODO: This really need a better way to handle these two windows (of which one is optional)...
|
||||
if (bottomPanel->GetChildren().size() != 0)
|
||||
return std::make_pair(sidePanel, bottomPanel);
|
||||
else
|
||||
{
|
||||
bottomPanel->Destroy();
|
||||
return std::make_pair(sidePanel, static_cast<wxPanel*>(NULL));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TYPE(elem) BOOST_PP_TUPLE_ELEM(2, 0, elem)
|
||||
|
@ -33,9 +33,7 @@
|
||||
|
||||
#include "js/jsapi.h"
|
||||
|
||||
class wxWindow;
|
||||
class wxString;
|
||||
class wxPanel;
|
||||
|
||||
namespace AtlasMessage { struct mWorldCommand; }
|
||||
typedef void (*SubmitCommand)(AtlasMessage::mWorldCommand* command);
|
||||
@ -68,8 +66,6 @@ public:
|
||||
// in ScriptInterface.cpp, else you'll end up with linker errors.)
|
||||
|
||||
void LoadScript(const wxString& filename, const wxString& code);
|
||||
wxPanel* LoadScriptAsPanel(const wxString& name, wxWindow* parent);
|
||||
std::pair<wxPanel*, wxPanel*> LoadScriptAsSidebar(const wxString& name, wxWindow* side, wxWindow* bottom);
|
||||
|
||||
// Convert a jsval to a C++ type. (This might trigger GC.)
|
||||
template <typename T> static bool FromJSVal(JSContext* cx, jsval val, T& ret);
|
||||
|
@ -350,42 +350,6 @@ END_EVENT_TABLE()
|
||||
static AtlasWindowCommandProc g_CommandProc;
|
||||
AtlasWindowCommandProc& ScenarioEditor::GetCommandProc() { return g_CommandProc; }
|
||||
|
||||
namespace
|
||||
{
|
||||
// Wrapper functions for scripts
|
||||
|
||||
void SetCurrentTool_(void* cbdata, wxString name)
|
||||
{
|
||||
static_cast<ScenarioEditor*>(cbdata)->GetToolManager().SetCurrentTool(name);
|
||||
}
|
||||
|
||||
void SetCurrentToolWith(void* cbdata, wxString name, wxString arg)
|
||||
{
|
||||
static_cast<ScenarioEditor*>(cbdata)->GetToolManager().SetCurrentTool(name, &arg);
|
||||
}
|
||||
|
||||
void SetCurrentToolWithVal(void* cbdata, wxString name, CScriptVal arg)
|
||||
{
|
||||
jsval tool = arg.get();
|
||||
static_cast<ScenarioEditor*>(cbdata)->GetToolManager().SetCurrentTool(name, &tool);
|
||||
}
|
||||
|
||||
wxString GetDataDirectory(void*)
|
||||
{
|
||||
return Datafile::GetDataDirectory();
|
||||
}
|
||||
|
||||
// TODO: see comment in terrain.js, and remove this when/if it's no longer necessary
|
||||
void SetBrushStrength(void*, float strength)
|
||||
{
|
||||
g_Brush_Elevation.SetStrength(strength);
|
||||
}
|
||||
void SetSelectedTexture(void*, wxString name)
|
||||
{
|
||||
g_SelectedTexture = name;
|
||||
}
|
||||
}
|
||||
|
||||
ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterface)
|
||||
: wxFrame(parent, wxID_ANY, _T(""), wxDefaultPosition, wxSize(1024, 768))
|
||||
, m_FileHistory(_T("Scenario Editor")), m_ScriptInterface(scriptInterface)
|
||||
@ -413,53 +377,6 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterfac
|
||||
|
||||
wxImage::AddHandler(new wxPNGHandler);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Script interface functions
|
||||
GetScriptInterface().SetCallbackData(static_cast<void*>(this));
|
||||
GetScriptInterface().RegisterFunction<wxString, GetDataDirectory>("GetDataDirectory");
|
||||
GetScriptInterface().RegisterFunction<void, wxString, SetCurrentTool_>("SetCurrentTool");
|
||||
GetScriptInterface().RegisterFunction<void, wxString, wxString, SetCurrentToolWith>("SetCurrentToolWith");
|
||||
GetScriptInterface().RegisterFunction<void, wxString, CScriptVal, SetCurrentToolWithVal>("SetCurrentToolWithVal");
|
||||
GetScriptInterface().RegisterFunction<void, float, SetBrushStrength>("SetBrushStrength");
|
||||
GetScriptInterface().RegisterFunction<void, wxString, SetSelectedTexture>("SetSelectedTexture");
|
||||
|
||||
{
|
||||
const wxString relativePath (_T("tools/atlas/scripts/main.js"));
|
||||
wxFileName filename (relativePath, wxPATH_UNIX);
|
||||
filename.MakeAbsolute(Datafile::GetDataDirectory());
|
||||
wxFFile file (filename.GetFullPath());
|
||||
wxString script;
|
||||
if (! file.ReadAll(&script))
|
||||
{
|
||||
wxLogError(_("Failed to read script"));
|
||||
}
|
||||
GetScriptInterface().LoadScript(filename.GetFullName(), script);
|
||||
}
|
||||
|
||||
// Load common scripts
|
||||
const wxString commonPath(_T("tools/atlas/scripts/common/"));
|
||||
wxFileName filename(commonPath, wxPATH_UNIX);
|
||||
filename.MakeAbsolute(Datafile::GetDataDirectory());
|
||||
wxArrayString filenames;
|
||||
if (wxDir::GetAllFiles(filename.GetFullPath(), &filenames, _T("*.js")) > 0)
|
||||
{
|
||||
for (size_t i = 0; i < filenames.GetCount(); ++i)
|
||||
{
|
||||
wxFFile file (filenames[i]);
|
||||
wxString script;
|
||||
if (! file.ReadAll(&script))
|
||||
{
|
||||
wxLogError(_("Failed to read script"));
|
||||
}
|
||||
GetScriptInterface().LoadScript(filename.GetFullName(), script);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogError(_("Failed to read common scripts directory"));
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Do some early game initialisation:
|
||||
|
@ -248,29 +248,6 @@ void SidebarButton::OnClick(wxCommandEvent& WXUNUSED(event))
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class ScriptedSidebar : public Sidebar
|
||||
{
|
||||
public:
|
||||
ScriptedSidebar(const wxString& name, ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
|
||||
: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer), m_BottomBarContainer(bottomBarContainer), m_Name(name)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void OnFirstDisplay()
|
||||
{
|
||||
Freeze();
|
||||
std::pair<wxPanel*, wxPanel*> panels = m_ScenarioEditor.GetScriptInterface().LoadScriptAsSidebar(_T("section/") + m_Name, this, m_BottomBarContainer);
|
||||
m_MainSizer->Add(panels.first, wxSizerFlags(1).Expand());
|
||||
m_BottomBar = panels.second;
|
||||
Layout();
|
||||
Thaw();
|
||||
}
|
||||
private:
|
||||
wxString m_Name;
|
||||
wxWindow* m_BottomBarContainer;
|
||||
};
|
||||
|
||||
|
||||
SectionLayout::SectionLayout()
|
||||
{
|
||||
}
|
||||
@ -310,13 +287,6 @@ void SectionLayout::Build(ScenarioEditor& scenarioEditor)
|
||||
m_SidebarBook->AddPage(sidebar, icon, tooltip); \
|
||||
m_PageMappings.insert(std::make_pair(L###classname, (int)m_SidebarBook->GetPageCount()-1));
|
||||
|
||||
#define ADD_SIDEBAR_SCRIPT(name, icon, tooltip) \
|
||||
sidebar = new ScriptedSidebar(name, scenarioEditor, m_SidebarBook->GetContentWindow(), m_VertSplitter); \
|
||||
if (sidebar->GetBottomBar()) \
|
||||
sidebar->GetBottomBar()->Show(false); \
|
||||
m_SidebarBook->AddPage(sidebar, icon, tooltip); \
|
||||
m_PageMappings.insert(std::make_pair(name, (int)m_SidebarBook->GetPageCount()-1));
|
||||
|
||||
ADD_SIDEBAR(MapSidebar, _T("map.png"), _("Map"));
|
||||
ADD_SIDEBAR(TerrainSidebar, _T("terrain.png"), _("Terrain"));
|
||||
ADD_SIDEBAR(ObjectSidebar, _T("object.png"), _("Object"));
|
||||
|
@ -1,96 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ScenarioEditor/ScenarioEditor.h"
|
||||
#include "AtlasScript/ScriptInterface.h"
|
||||
|
||||
class ScriptedTool : public StateDrivenTool<ScriptedTool>
|
||||
{
|
||||
DECLARE_DYNAMIC_CLASS(ScriptedTool);
|
||||
|
||||
jsval m_Tool;
|
||||
ScriptInterface* m_ScriptInterface;
|
||||
|
||||
public:
|
||||
ScriptedTool()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Init(void* initData, ScenarioEditor* scenarioEditor)
|
||||
{
|
||||
StateDrivenTool<ScriptedTool>::Init(initData, scenarioEditor);
|
||||
|
||||
m_ScriptInterface = &scenarioEditor->GetScriptInterface();
|
||||
wxASSERT(initData);
|
||||
jsval& tool = *static_cast<jsval*>(initData);
|
||||
m_Tool = tool;
|
||||
m_ScriptInterface->AddRoot(&m_Tool);
|
||||
|
||||
SetState(&Running);
|
||||
}
|
||||
|
||||
virtual void Shutdown()
|
||||
{
|
||||
m_ScriptInterface->RemoveRoot(&m_Tool);
|
||||
|
||||
StateDrivenTool<ScriptedTool>::Shutdown();
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_ScriptInterface->CallFunction(m_Tool, "onEnable");
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
m_ScriptInterface->CallFunction(m_Tool, "onDisable");
|
||||
}
|
||||
|
||||
struct sRunning : public State
|
||||
{
|
||||
bool OnMouse(ScriptedTool* obj, wxMouseEvent& evt)
|
||||
{
|
||||
bool ret;
|
||||
if (! obj->m_ScriptInterface->CallFunction(obj->m_Tool, "onMouse", evt, ret))
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
bool OnKey(ScriptedTool* obj, wxKeyEvent& evt, KeyEventType type)
|
||||
{
|
||||
wxString typeStr;
|
||||
switch (type) {
|
||||
case KEY_DOWN: typeStr = _T("down"); break;
|
||||
case KEY_UP: typeStr = _T("up"); break;
|
||||
case KEY_CHAR: typeStr = _T("char"); break;
|
||||
}
|
||||
bool ret;
|
||||
if (! obj->m_ScriptInterface->CallFunction(obj->m_Tool, "onKey", evt, typeStr, ret))
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
void OnTick(ScriptedTool* obj, float dt)
|
||||
{
|
||||
bool ret;
|
||||
obj->m_ScriptInterface->CallFunction(obj->m_Tool, "onTick", dt, ret);
|
||||
}
|
||||
}
|
||||
Running;
|
||||
};
|
||||
|
||||
IMPLEMENT_DYNAMIC_CLASS(ScriptedTool, StateDrivenTool<ScriptedTool>);
|
Loading…
Reference in New Issue
Block a user