Integrates random maps with Atlas. Fixes #460.

Adds various map controls to Atlas.
Adds New Map dialog to Atlas.
Removes a few references to old simulation header files.

This was SVN commit r9247.
This commit is contained in:
historic_bruno 2011-04-14 04:01:59 +00:00
parent 3b8e216622
commit ad6f305359
20 changed files with 1118 additions and 494 deletions

View File

@ -46,14 +46,24 @@
<playercolours>
<colour name="Gaia" rgb="255 255 255"/>
<colour name="Player 1" rgb="111 111 207" buttontext="255 255 255"/>
<colour name="Player 2" rgb="207 111 111" buttontext="255 255 255"/>
<colour name="Player 3" rgb="111 207 111" buttontext="255 255 255"/>
<colour name="Player 4" rgb="207 207 111" buttontext="255 255 255"/>
<colour name="Player 5" rgb="111 207 207" buttontext="255 255 255"/>
<colour name="Player 6" rgb="207 111 207" buttontext="255 255 255"/>
<colour name="Player 7" rgb="207 159 111" buttontext="255 255 255"/>
<colour name="Player 8" rgb="159 159 159" buttontext="255 255 255"/>
<colour name="Player 1" rgb="80 80 200" buttontext="255 255 255"/>
<colour name="Player 2" rgb="150 20 20" buttontext="255 255 255"/>
<colour name="Player 3" rgb="50 165 5" buttontext="255 255 255"/>
<colour name="Player 4" rgb="230 230 75" buttontext="255 255 255"/>
<colour name="Player 5" rgb="50 170 170" buttontext="255 255 255"/>
<colour name="Player 6" rgb="160 80 200" buttontext="255 255 255"/>
<colour name="Player 7" rgb="230 120 20" buttontext="255 255 255"/>
<colour name="Player 8" rgb="64 64 64" buttontext="255 255 255"/>
</playercolours>
<mapsizes>
<size name="Tiny" patches="8"/>
<size name="Small" patches="12"/>
<size name="Medium" patches="16"/>
<size name="Normal" patches="20"/>
<size name="Large" patches="24"/>
<size name="Very Large" patches="28"/>
<size name="Giant" patches="32"/>
</mapsizes>
</lists>

View File

@ -0,0 +1,139 @@
//////////////////////////////////////////////////////////////////////////////
// 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
}
}

View File

@ -38,7 +38,7 @@ defaults.objectSettings.onSelectionChange = function () {
if (settings.player != -1)
this.playerID = settings.player;
this.actorSelections = settings.selections;
this.variantGroups = settings.variantgroups;
this.variantGroups = settings.variantGroups;
}
this.notifyObservers();
}

View File

@ -1,4 +1,5 @@
function setupSimTest(window)
function setupSimTest(window, rmsPanel)
{
var state = 'inactive'; // inactive, playing
var speed = 0;
@ -32,7 +33,19 @@ function setupSimTest(window)
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 ];
@ -56,67 +69,468 @@ function setupSimTest(window)
}
updateEnableStatus();
window.sizer.add(sizer, 0, wxStretch.EXPAND | wxDirection.LEFT|wxDirection.RIGHT, 2);
var dumpDisplayButton = new wxButton(window, -1, 'Display sim state');
dumpDisplayButton.onClicked = function ()
{
var state = Atlas.Message.SimStateDebugDump(false).dump;
if (state.length > 10240) // avoid giant message boxes that crash
state = state.substr(0, 10240)+"...";
wxMessageBox(state);
};
window.sizer.add(dumpDisplayButton);
var dumpButton = new wxButton(window, -1, 'Dump sim state to disk');
dumpButton.toolTip = 'Saves to sim-dump-$(TIMESTAMP).txt in working directory';
dumpButton.onClicked = function () {
var filename = 'sim-dump-' + (new Date().getTime()) + '.txt';
var state = Atlas.Message.SimStateDebugDump(false).dump;
var file = new wxFFile(filename, 'w'); // TODO: error check
file.write(state);
file.close();
};
window.sizer.add(dumpButton);
var dumpBinButton = new wxButton(window, -1, 'Dump binary sim state to disk');
dumpBinButton.toolTip = 'Saves to sim-dump-$(TIMESTAMP).dat in working directory';
dumpBinButton.onClicked = function () {
var filename = 'sim-dump-' + (new Date().getTime()) + '.dat';
var state = Atlas.Message.SimStateDebugDump(true).dump;
var file = new wxFFile(filename, 'w'); // TODO: error check
file.write(state);
file.close();
};
window.sizer.add(dumpBinButton);
}
function generateRMS(name)
//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)
{
var cwd = wxFileName.cwd;
wxFileName.cwd = Atlas.GetDataDirectory();
var ret = wxExecute([ 'rmgen.exe', name, '_atlasrm' ], wxExecFlag.SYNC); // TODO: portability
wxFileName.cwd = cwd;
if (ret == 0)
Atlas.Message.LoadMap('_atlasrm.pmp');
else
wxMessageBox('Failed to run rmgen (error code: '+ret+')');
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 getStartingData()
{
// Load civilization data
if (!Atlas.State.CivData)
{
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);
}
}
}
}
// Load player default data (names, civs, colors, etc)
if (!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);
var button = new wxButton(window, -1, 'Generate empty map');
button.onClicked = function () { Atlas.Message.GenerateMap(9); };
window.sizer.add(button, 0, wxDirection.ALL, 2);
// 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);
var sizer = new wxBoxSizer(wxOrientation.HORIZONTAL);
var rmsFilename = new wxTextCtrl(window, -1, 'cantabrian_highlands');
var rmsButton = new wxButton(window, -1, 'Run RMS');
rmsButton.onClicked = function () { generateRMS(rmsFilename.value) }
sizer.add(rmsFilename, 1);
sizer.add(rmsButton, 0);
window.sizer.add(sizer, 0, wxStretch.EXPAND | wxDirection.ALL, 2);
settingsSizer.add(5, 5, 0); // Add space
setupSimTest(window);
// 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);
var keywords = ["demo", "hidden"];
var keywordCtrl = new wxListBox(window, -1, wxDefaultPosition, wxDefaultSize, keywords, wxListBox.MULTIPLE);
keywordCtrl.toolTip = 'Select keyword(s) to apply to this map';
keywordCtrl.onListBox = function()
{
var kws = [];
// Convert selections to keywords array
var selections = this.selections;
for (var i = 0; i < selections.length; ++i)
{
kws.push(keywords[selections[i]]);
}
Atlas.State.mapSettings.settings.Keywords = kws;
};
function updateKeywords()
{
var kws = Atlas.State.mapSettings.settings.Keywords;
if (kws)
{
for (var i = 0; i < kws.length; ++i)
{
var idx = keywords.indexOf(kws[i]);
if (idx != -1)
{
// TODO: There doesn't appear to be a way to set selections
}
else
{ // New keyword, add to list
keywordCtrl.insertItems([kws[i]]);
}
}
}
}
keywordSizer.add(keywordCtrl, 0, wxStretch.EXPAND);
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);
var scriptNames = [];
var scriptData = [];
boxSizer = new wxBoxSizer(wxOrientation.HORIZONTAL);
var rmsChoice = new wxChoice(rmsPanel, -1, wxDefaultPosition, wxDefaultSize, scriptNames);
rmsChoice.toolTip = "Select the random map script to run";
function loadScriptChoices()
{
// Reload RMS data
scriptNames = [];
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)
{
scriptData.push(data);
scriptNames.push(data.settings.Name);
}
}
// Add script names to choice control
rmsChoice.clear();
rmsChoice.append(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 sizePatches = [8, 12, 16, 20, 24, 28, 32];
var sizeChoice = new wxChoice(rmsPanel, -1, wxDefaultPosition, wxDefaultSize, sizeNames);
var numChoices = sizeNames.length;
sizeChoice.toolTip = 'Select the desired map size\n'+sizeNames[0]+' = '+sizePatches[0]+' patches, '+sizeNames[numChoices-1]+' = '+sizePatches[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 = scriptData[selection].settings;
if (RMSData)
{
if (useRandomCtrl.value)
{ // Generate random seed
generateRandomSeed();
}
// Base terrains must be array
var terrainArray = [];
if (RMSData.BaseTerrain instanceof Array)
{
terrainArray = RMSData.BaseTerrain;
}
else
{ // Add string to array
terrainArray.push(RMSData.BaseTerrain);
}
// Stringify player data
var pDataStr = JSON.stringify(Atlas.State.mapSettings.settings.PlayerData);
// Generate map
var ret = Atlas.Message.GenerateMap(
RMSData.Script,
sizePatches[sizeChoice.selection],
Atlas.State.Seed ? Atlas.State.Seed : 0,
terrainArray,
RMSData.BaseHeight,
pDataStr
);
// 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)
{
// If we don't have civ data or player defaults yet, get those
getStartingData();
// Load map settings from engine
getMapSettings();
// Load RMS names from engine
loadScriptChoices();
// 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);
}

View File

@ -55,111 +55,6 @@ var brush = {
}
};
var lastTerrainSelection = null; // button that was last selected, so we can undo its colouring
function onTerrainSelect()
{
Atlas.SetSelectedTexture(this.terrainName);
if (lastTerrainSelection)
lastTerrainSelection.backgroundColour = wxNullColour;
this.backgroundColour = new wxColour(255, 255, 0);
lastTerrainSelection = this;
}
function TerrainPreviewPage(panel, name)
{
this.panel = panel;
this.name = name;
// Size of texture preview images
this.w = 120
this.h = 40;
this.previewReloadTimer = null;
}
TerrainPreviewPage.prototype = {
reloadPreviews: function() {
this.panel.freeze();
this.scrolled.destroyChildren();
this.itemSizer.clear();
lastTerrainSelection = null; // clear any reference to deleted window
// TODO: Do something clever like load the preview images asynchronously,
// to avoid the annoying freeze when switching tabs
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);
button.terrainName = p.name;
button.onClicked = onTerrainSelect;
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;
}
};
function init(window, bottomWindow)
{
window.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
@ -256,7 +151,7 @@ function init(window, bottomWindow)
visualiseSizer.add(visualiseSettingsSizer);
visualiseSettingsSizer.add(new wxStaticText(window, -1, 'Passability'), 0, wxAlignment.RIGHT);
var passabilityClasses = Atlas.Message.GetTerrainPassabilityClasses().classnames;
var passabilityClasses = Atlas.Message.GetTerrainPassabilityClasses().classNames;
var passabilitySelector = new wxChoice(window, -1, wxDefaultPosition, wxDefaultSize,
["(none)"].concat(passabilityClasses)
);
@ -287,11 +182,11 @@ function init(window, bottomWindow)
pages[evt.selection].display()
evt.skip = true;
}
for each (var groupname in terrainGroups.groupnames)
for each (var groupName in terrainGroups.groupNames)
{
var panel = new wxPanel(nb, -1);
var page = new TerrainPreviewPage(panel, groupname);
var page = new global.TerrainPreviewPage(panel, groupName);
pages.push(page);
nb.addPage(panel, groupname); // TODO: use Titlecase letters
nb.addPage(panel, groupName); // TODO: use Titlecase letters
}
}

View File

@ -0,0 +1,21 @@
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
}
}

View File

@ -811,6 +811,7 @@ function setup_atlas_packages()
"CustomControls/EditableListCtrl",
"CustomControls/FileHistory",
"CustomControls/HighResTimer",
"CustomControls/NewDialog",
"CustomControls/SnapSplitterWindow",
"CustomControls/VirtualDirTreeCtrl",
"CustomControls/Windows",
@ -822,9 +823,6 @@ function setup_atlas_packages()
"ScenarioEditor/Sections/Common",
"ScenarioEditor/Sections/Cinematic",
"ScenarioEditor/Sections/Environment",
"ScenarioEditor/Sections/Map",
"ScenarioEditor/Sections/Object",
"ScenarioEditor/Sections/Terrain",
"ScenarioEditor/Sections/Trigger",
"ScenarioEditor/Tools",
"ScenarioEditor/Tools/Common",

View File

@ -52,7 +52,6 @@
#include "renderer/Renderer.h"
#include "renderer/WaterManager.h"
#include "scripting/ScriptableObject.h"
#include "simulation/LOSManager.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpPosition.h"
#include "simulation2/components/ICmpRangeManager.h"

View File

@ -517,3 +517,104 @@ std::string CSimulation2::GenerateSchema()
{
return m->m_ComponentManager.GenerateSchema();
}
std::vector<std::string> CSimulation2::GetRMSData()
{
VfsPath path(L"maps/random/");
VfsPaths pathnames;
std::vector<std::string> data;
// Find all ../maps/random/*.json
LibError ret = fs_util::GetPathnames(g_VFS, path, L"*.json", pathnames);
if (ret == INFO::OK)
{
for (VfsPaths::iterator it = pathnames.begin(); it != pathnames.end(); ++it)
{
// Load JSON file
CVFSFile file;
PSRETURN ret = file.Load(g_VFS, *it);
if (ret != PSRETURN_OK)
{
LOGERROR(L"Failed to load file '%ls': %hs", path.string().c_str(), GetErrorString(ret));
}
else
{
data.push_back(std::string(file.GetBuffer(), file.GetBuffer() + file.GetBufferSize()));
}
}
}
else
{
// Some error reading directory
wchar_t error[200];
LOGERROR(L"Error reading directory '%ls': %hs", path.string().c_str(), error_description_r(ret, error, ARRAY_SIZE(error)));
}
return data;
}
std::vector<std::string> CSimulation2::GetCivData()
{
VfsPath path(L"civs/");
VfsPaths pathnames;
std::vector<std::string> data;
// Load all JSON files in civs directory
LibError ret = fs_util::GetPathnames(g_VFS, path, L"*.json", pathnames);
if (ret == INFO::OK)
{
for (VfsPaths::iterator it = pathnames.begin(); it != pathnames.end(); ++it)
{
// Load JSON file
CVFSFile file;
PSRETURN ret = file.Load(g_VFS, *it);
if (ret != PSRETURN_OK)
{
LOGERROR(L"Failed to load file '%ls': %hs", path.string().c_str(), GetErrorString(ret));
}
else
{
data.push_back(std::string(file.GetBuffer(), file.GetBuffer() + file.GetBufferSize()));
}
}
}
else
{
// Some error reading directory
wchar_t error[200];
LOGERROR(L"Error reading directory '%ls': %hs", path.string().c_str(), error_description_r(ret, error, ARRAY_SIZE(error)));
}
// Convert from vector to array and stringify
return data;
}
std::string CSimulation2::GetPlayerDefaults()
{
VfsPath path = VfsPath(L"simulation/data/player_defaults.json");
std::string data;
if (!VfsFileExists(g_VFS, path))
{
LOGERROR(L"File '%ls' does not exist", path.string().c_str());
}
else
{
// Load JSON file
CVFSFile file;
PSRETURN ret = file.Load(g_VFS, path);
if (ret != PSRETURN_OK)
{
LOGERROR(L"Failed to load file '%ls': %hs", path.string().c_str(), GetErrorString(ret));
}
else
{
data = std::string(file.GetBuffer(), file.GetBuffer() + file.GetBufferSize());
}
}
return data;
}

View File

@ -202,6 +202,30 @@ public:
std::string GenerateSchema();
/////////////////////////////////////////////////////////////////////////////
// Some functions for Atlas UI to be able to access VFS data
/**
* Get random map script data
*
* @return vector of strings containing JSON format data
*/
std::vector<std::string> GetRMSData();
/**
* Get civilization data
*
* @return vector of strings containing JSON format data
*/
std::vector<std::string> GetCivData();
/**
* Get player default data
*
* @return string containing JSON format data
*/
std::string GetPlayerDefaults();
private:
CSimulation2Impl* m;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -259,9 +259,13 @@ namespace
template<> struct ToJSVal<size_t>
{
static jsval Convert(JSContext* WXUNUSED(cx), const size_t& val)
static jsval Convert(JSContext* cx, const size_t& val)
{
return INT_TO_JSVAL(val);
if (val <= JSVAL_INT_MAX)
return INT_TO_JSVAL(val);
jsval rval = JSVAL_VOID;
JS_NewNumberValue(cx, val, &rval); // ignore return value
return rval;
}
};
@ -295,6 +299,17 @@ namespace
}
};
template<> struct ToJSVal<std::string>
{
static jsval Convert(JSContext* cx, const std::string& val)
{
JSString* str = JS_NewStringCopyN(cx, val.c_str(), val.length());
if (str)
return STRING_TO_JSVAL(str);
return JSVAL_VOID;
}
};
////////////////////////////////////////////////////////////////
// wxJS types:
@ -388,9 +403,9 @@ namespace
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)));
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);
@ -418,7 +433,7 @@ namespace
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);
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);
}
};

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -33,6 +33,7 @@
#include "CustomControls/HighResTimer/HighResTimer.h"
#include "CustomControls/Buttons/ToolButton.h"
#include "CustomControls/Canvas/Canvas.h"
#include "CustomControls/NewDialog/NewDialog.h"
#include "GameInterface/MessagePasser.h"
#include "GameInterface/Messages.h"
@ -301,7 +302,7 @@ enum
{
ID_Quit = 1,
// ID_New,
ID_New,
ID_Open,
ID_Save,
ID_SaveAs,
@ -313,6 +314,8 @@ enum
ID_CameraReset,
ID_RenderPathFixed,
ID_RenderPathShader,
ID_DumpState,
ID_DumpBinaryState,
ID_Toolbar // must be last in the list
};
@ -321,7 +324,7 @@ BEGIN_EVENT_TABLE(ScenarioEditor, wxFrame)
EVT_CLOSE(ScenarioEditor::OnClose)
EVT_TIMER(wxID_ANY, ScenarioEditor::OnTimer)
// EVT_MENU(ID_New, ScenarioEditor::OnNew)
EVT_MENU(ID_New, ScenarioEditor::OnNew)
EVT_MENU(ID_Open, ScenarioEditor::OnOpen)
EVT_MENU(ID_Save, ScenarioEditor::OnSave)
EVT_MENU(ID_SaveAs, ScenarioEditor::OnSaveAs)
@ -336,6 +339,8 @@ BEGIN_EVENT_TABLE(ScenarioEditor, wxFrame)
EVT_MENU(ID_Screenshot, ScenarioEditor::OnScreenshot)
EVT_MENU(ID_JavaScript, ScenarioEditor::OnJavaScript)
EVT_MENU(ID_CameraReset, ScenarioEditor::OnCameraReset)
EVT_MENU(ID_DumpState, ScenarioEditor::OnDumpState)
EVT_MENU(ID_DumpBinaryState, ScenarioEditor::OnDumpState)
EVT_MENU(ID_RenderPathFixed, ScenarioEditor::OnRenderPath)
EVT_MENU(ID_RenderPathShader, ScenarioEditor::OnRenderPath)
@ -425,10 +430,36 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterfac
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"));
}
// Initialise things that rely on scripts
m_ObjectSettings.Init(AtlasMessage::eRenderView::GAME);
@ -452,7 +483,7 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterfac
wxMenu *menuFile = new wxMenu;
menuBar->Append(menuFile, _("&File"));
{
// menuFile->Append(ID_New, _("&New"));
menuFile->Append(ID_New, _("&New..."));
menuFile->Append(ID_Open, _("&Open..."));
menuFile->Append(ID_Save, _("&Save"));
menuFile->Append(ID_SaveAs, _("Save &As..."));
@ -485,6 +516,11 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterfac
menuMisc->Append(ID_JavaScript, _("&JS console"));
menuMisc->Append(ID_CameraReset, _("&Reset camera"));
wxMenu *menuSS = new wxMenu;
menuMisc->AppendSubMenu(menuSS, _("Si&mulation state"));
menuSS->Append(ID_DumpState, _("&Dump to disk"));
menuSS->Append(ID_DumpBinaryState, _("Dump &binary to disk"));
wxMenu *menuRP = new wxMenu;
menuMisc->AppendSubMenu(menuRP, _("Render &path"));
menuRP->Append(ID_RenderPathFixed, _("&Fixed function"));
@ -554,7 +590,13 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterfac
// Start with a blank map (so that the editor can assume there's always
// a valid map loaded)
POST_MESSAGE(GenerateMap, (9));
POST_MESSAGE(LoadMap, (_T("_default")));
// Wait for blank map
qry.Post();
// Notify UI scripts that map settings have been loaded
m_ScriptInterface.Eval(_T("Atlas.State.mapSettings.notifyObservers()"));
POST_MESSAGE(RenderEnable, (eRenderView::GAME));
@ -640,6 +682,51 @@ void ScenarioEditor::OnRedo(wxCommandEvent&)
//////////////////////////////////////////////////////////////////////////
void ScenarioEditor::OnNew(wxCommandEvent& WXUNUSED(event))
{
NewDialog dlg(NULL, _("Create new map"), wxSize(600, 400), *this);
if(dlg.ShowModal() == wxID_OK)
{
wxBusyInfo busy(_("Creating blank map"));
// Generate new blank map
size_t patches = dlg.GetSelectedSize();
size_t height = dlg.GetBaseHeight();
// Get terrain texture
// TODO: Support choosing multiple textures
std::vector<std::wstring> textures;
std::wstring baseTexture(g_SelectedTexture.wc_str());
textures.push_back(baseTexture);
// Get player data
std::string pData;
m_ScriptInterface.Eval(_T("JSON.stringify(Atlas.State.mapSettings.settings.PlayerData)"), pData);
// Generate map
// Script name, size (patches), seed, base terrain(s), base height, player data
qGenerateMap qry(L"blank.js", patches, 0, textures, height, pData);
// Wait for map generation to finish
qry.Post();
if (qry.status < 0)
{ // Map generation failed
wxMessageDialog msgDlg(NULL, _T("Random map script 'blank.js'. Loading blank map."), _T("Error"), wxICON_ERROR);
qPing pingQry;
POST_MESSAGE(LoadMap, (_T("_default")));
// Wait for blank map
pingQry.Post();
}
// Notify UI scripts that map settings have been loaded
m_ScriptInterface.Eval(_T("Atlas.State.mapSettings.notifyObservers()"));
}
}
void ScenarioEditor::OpenFile(const wxString& name)
{
wxBusyInfo busy(_("Loading map"));
@ -661,6 +748,9 @@ void ScenarioEditor::OpenFile(const wxString& name)
qPing qry;
qry.Post();
// Notify UI scripts that map settings have been loaded
m_ScriptInterface.Eval(_T("Atlas.State.mapSettings.notifyObservers()"));
// TODO: Make this a non-undoable command
}
@ -687,15 +777,25 @@ void ScenarioEditor::OnOpen(wxCommandEvent& WXUNUSED(event))
void ScenarioEditor::OnMRUFile(wxCommandEvent& event)
{
wxString file (m_FileHistory.GetHistoryFile(event.GetId() - wxID_FILE1));
if (file.Len())
OpenFile(file);
wxString filename(m_FileHistory.GetHistoryFile(event.GetId() - wxID_FILE1));
if (filename.Len())
{
OpenFile(filename);
}
else
{ //Remove from MRU
m_FileHistory.RemoveFileFromHistory(event.GetId() - wxID_FILE1);
wxMessageDialog msgDlg(NULL, _T("File '/mods/*/maps/scenarios/")+filename + _T("' does not exist!"), _T("Error"), wxICON_ERROR);
msgDlg.ShowModal();
}
}
void ScenarioEditor::OnSave(wxCommandEvent& event)
{
if (m_OpenFilename.IsEmpty())
{
OnSaveAs(event);
}
else
{
wxBusyInfo busy(_("Saving map"));
@ -705,11 +805,22 @@ void ScenarioEditor::OnSave(wxCommandEvent& event)
// the preview units.)
m_ToolManager.SetCurrentTool(_T(""));
qPing qry;
// Save map settings
std::string settings;
if (m_ScriptInterface.Eval(_T("JSON.stringify(Atlas.State.mapSettings.settings)"), settings))
{
POST_MESSAGE(SetMapSettings, (settings));
// Wait for it to finish saving
qry.Post();
}
std::wstring map = m_OpenFilename.c_str();
POST_MESSAGE(SaveMap, (map));
// Wait for it to finish saving
qPing qry;
qry.Post();
}
}
@ -727,6 +838,18 @@ void ScenarioEditor::OnSaveAs(wxCommandEvent& WXUNUSED(event))
m_ToolManager.SetCurrentTool(_T(""));
qPing qry;
// Save map settings
std::string settings;
if (m_ScriptInterface.Eval(_T("JSON.stringify(Atlas.State.mapSettings.settings)"), settings))
{
POST_MESSAGE(SetMapSettings, (settings));
// Wait for it to finish saving
qry.Post();
}
// TODO: Work when the map is not in .../maps/scenarios/
std::wstring map = dlg.GetFilename().c_str();
POST_MESSAGE(SaveMap, (map));
@ -734,7 +857,6 @@ void ScenarioEditor::OnSaveAs(wxCommandEvent& WXUNUSED(event))
SetOpenFilename(dlg.GetFilename());
// Wait for it to finish saving
qPing qry;
qry.Post();
}
}
@ -793,6 +915,42 @@ void ScenarioEditor::OnRenderPath(wxCommandEvent& event)
}
}
void ScenarioEditor::OnDumpState(wxCommandEvent& event)
{
wxDateTime time = wxDateTime::Now();
wxString filename;
bool doBinary = false;
switch (event.GetId())
{
case ID_DumpState:
filename = wxString::Format(_T("sim-dump-%d.txt"), time.GetTicks());
break;
case ID_DumpBinaryState:
doBinary = true;
filename = wxString::Format(_T("sim-dump-%d.dat"), time.GetTicks());
break;
}
qSimStateDebugDump q(doBinary);
q.Post();
wxString state(std::wstring(*q.dump));
wxFFile file(filename.c_str(), _T("w"));
if (file.IsOpened() && !file.Error())
{
file.Write(state);
file.Close();
}
else
{
wxMessageDialog msgDlg(NULL, _("Error writing to file: ") + filename, _("Error"), wxICON_ERROR);
msgDlg.ShowModal();
}
}
//////////////////////////////////////////////////////////////////////////
Position::Position(const wxPoint& pt)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -35,7 +35,7 @@ public:
void OnTimer(wxTimerEvent& event);
void OnIdle(wxIdleEvent& event);
// void OnNew(wxCommandEvent& event);
void OnNew(wxCommandEvent& event);
void OnOpen(wxCommandEvent& event);
void OnSave(wxCommandEvent& event);
void OnSaveAs(wxCommandEvent& event);
@ -52,6 +52,7 @@ public:
void OnJavaScript(wxCommandEvent& event);
void OnCameraReset(wxCommandEvent& event);
void OnRenderPath(wxCommandEvent& event);
void OnDumpState(wxCommandEvent& event);
void OpenFile(const wxString& name);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -27,7 +27,6 @@
#include "ScenarioEditor.h"
#include "AtlasScript/ScriptInterface.h"
#include "Sections/Terrain/Terrain.h"
#include "Sections/Environment/Environment.h"
#include "Sections/Cinematic/Cinematic.h"
#include "Sections/Trigger/Trigger.h"
@ -315,7 +314,6 @@ void SectionLayout::Build(ScenarioEditor& scenarioEditor)
ADD_SIDEBAR_SCRIPT(_T("map"), _T("map.png"), _("Map"));
ADD_SIDEBAR_SCRIPT(_T("terrain"), _T("terrain.png"), _("Terrain"));
//ADD_SIDEBAR(TerrainSidebar, _T("terrain.png"), _("Terrain"));
ADD_SIDEBAR_SCRIPT(_T("object"), _T("object.png"), _("Object"));
ADD_SIDEBAR(EnvironmentSidebar, _T("environment.png"), _("Environment"));

View File

@ -1,239 +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 "Terrain.h"
#include "Buttons/ToolButton.h"
#include "General/Datafile.h"
#include "ScenarioEditor/ScenarioEditor.h"
#include "ScenarioEditor/Tools/Common/Brushes.h"
#include "ScenarioEditor/Tools/Common/MiscState.h"
#include "GameInterface/Messages.h"
#include "wx/spinctrl.h"
#include "wx/listctrl.h"
#include "wx/image.h"
#include "wx/imaglist.h"
#include "wx/busyinfo.h"
#include "wx/notebook.h"
class TextureNotebook;
class TerrainBottomBar : public wxPanel
{
public:
TerrainBottomBar(wxWindow* parent);
void LoadTerrain();
private:
TextureNotebook* m_Textures;
};
TerrainSidebar::TerrainSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer)
{
// TODO: Less ugliness
m_MainSizer->Add(new wxStaticText(this, wxID_ANY, _T("TODO: Make this much less ugly\n")));
{
wxSizer* sizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Elevation tools"));
sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Modify"), _T("AlterElevation"), wxSize(50,20)));
sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Smooth"), _T("SmoothElevation"), wxSize(50,20)));
sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Flatten"), _T("FlattenElevation"), wxSize(50,20)));
// sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Smooth"), _T(""), wxSize(50,20)));
// sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Sample"), _T(""), wxSize(50,20)));
sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Paint"), _T("PaintTerrain"), wxSize(50,20)));
m_MainSizer->Add(sizer);
}
{
wxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Brush"));
g_Brush_Elevation.CreateUI(this, sizer);
m_MainSizer->Add(sizer);
}
m_BottomBar = new TerrainBottomBar(bottomBarContainer);
}
void TerrainSidebar::OnFirstDisplay()
{
static_cast<TerrainBottomBar*>(m_BottomBar)->LoadTerrain();
}
//////////////////////////////////////////////////////////////////////////
class TextureNotebookPage : public wxPanel
{
public:
TextureNotebookPage(wxWindow* parent, const wxString& name)
: wxPanel(parent, wxID_ANY), m_Name(name), m_ListCtrl(NULL)
{
}
void OnDisplay()
{
if (m_ListCtrl)
{
int sel = m_ListCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
if (sel != -1)
SetSelection(m_ListCtrl->GetItemData(sel));
return;
}
wxBusyInfo busy (_("Loading terrain previews"));
m_TextureNames.Clear();
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
m_ListCtrl = new wxListCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_ICON | wxLC_SINGLE_SEL | wxLC_AUTOARRANGE);
const int imageWidth = 64;
const int imageHeight = 32;
wxImageList* imglist = new wxImageList(imageWidth, imageHeight, false, 0);
AtlasMessage::qGetTerrainGroupPreviews qry(m_Name.c_str(), imageWidth, imageHeight);
qry.Post();
std::vector<AtlasMessage::sTerrainGroupPreview> previews = *qry.previews;
int i = 0;
for (std::vector<AtlasMessage::sTerrainGroupPreview>::iterator it = previews.begin(); it != previews.end(); ++it)
{
unsigned char* buf = (unsigned char*)(malloc(it->imagedata.GetSize()));
// it->imagedata.GetBuffer() gives a Shareable<unsigned char>*, which
// is stored the same as a unsigned char*, so we can just copy it.
memcpy(buf, it->imagedata.GetBuffer(), it->imagedata.GetSize());
wxImage img (imageWidth, imageHeight, buf);
imglist->Add(wxBitmap(img));
wxListItem item;
wxString name = it->name.c_str();
m_TextureNames.Add(name);
// Add spaces into the displayed name, so Windows doesn't just say
// "grass_..." in the list ctrl for every terrain
name.Replace(_T("_"), _T(" "));
item.SetText(name);
item.SetData(i);
item.SetId(i);
item.SetImage(i);
m_ListCtrl->InsertItem(item);
++i;
}
m_ListCtrl->AssignImageList(imglist, wxIMAGE_LIST_NORMAL);
sizer->Add(m_ListCtrl, wxSizerFlags().Expand().Proportion(1));
SetSizer(sizer);
Layout(); // required to make things size correctly
}
void OnSelect(wxListEvent& evt)
{
SetSelection(evt.GetData());
}
void SetSelection(int n)
{
if (n >= 0 && n < (int)m_TextureNames.GetCount())
g_SelectedTexture = m_TextureNames[n];
}
private:
wxListCtrl* m_ListCtrl;
wxString m_Name;
wxArrayString m_TextureNames;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(TextureNotebookPage, wxPanel)
EVT_LIST_ITEM_SELECTED(wxID_ANY, TextureNotebookPage::OnSelect)
END_EVENT_TABLE();
class TextureNotebook : public wxNotebook
{
public:
TextureNotebook(wxWindow *parent)
: wxNotebook(parent, wxID_ANY/*, wxDefaultPosition, wxDefaultSize, wxNB_FIXEDWIDTH*/)
{
}
void LoadTerrain()
{
wxBusyInfo busy (_("Loading terrain groups"));
DeleteAllPages();
m_TerrainGroups.Clear();
// Get the list of terrain groups from the engine
AtlasMessage::qGetTerrainGroups qry;
qry.Post();
std::vector<std::wstring> groupnames = *qry.groupnames;
for (std::vector<std::wstring>::iterator it = groupnames.begin(); it != groupnames.end(); ++it)
m_TerrainGroups.Add(it->c_str());
for (size_t i = 0; i < m_TerrainGroups.GetCount(); ++i)
{
wxString visibleName = m_TerrainGroups[i];
if (visibleName.Len())
visibleName[0] = wxToupper(visibleName[0]);
AddPage(new TextureNotebookPage(this, m_TerrainGroups[i]), visibleName);
}
}
protected:
void OnPageChanged(wxNotebookEvent& event)
{
if (event.GetSelection() >= 0 && event.GetSelection() < (int)GetPageCount())
{
static_cast<TextureNotebookPage*>(GetPage(event.GetSelection()))->OnDisplay();
}
event.Skip();
}
private:
wxArrayString m_TerrainGroups;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(TextureNotebook, wxNotebook)
EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, TextureNotebook::OnPageChanged)
END_EVENT_TABLE();
//////////////////////////////////////////////////////////////////////////
TerrainBottomBar::TerrainBottomBar(wxWindow* parent)
: wxPanel(parent, wxID_ANY)
{
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
m_Textures = new TextureNotebook(this);
sizer->Add(m_Textures, wxSizerFlags().Expand().Proportion(1));
SetSizer(sizer);
}
void TerrainBottomBar::LoadTerrain()
{
m_Textures->LoadTerrain();
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -31,8 +31,6 @@
#include "ps/World.h"
#include "renderer/Renderer.h"
#include "scriptinterface/ScriptInterface.h"
#include "simulation/LOSManager.h"
#include "simulation/Simulation.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpPlayer.h"
#include "simulation2/components/ICmpPlayerManager.h"
@ -55,16 +53,8 @@ namespace
g_Game->SetPlayerID(1);
}
void StartGame(const CStrW& map)
void StartGame(const CScriptValRooted& attrs)
{
CStrW mapBase = map.BeforeLast(L".pmp"); // strip the file extension, if any
ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
CScriptValRooted attrs;
scriptInterface.Eval("({})", attrs);
scriptInterface.SetProperty(attrs.get(), "mapType", std::string("scenario"), false);
scriptInterface.SetProperty(attrs.get(), "map", std::wstring(mapBase), false);
g_Game->StartGame(attrs);
// TODO: Non progressive load can fail - need a decent way to handle this
@ -82,22 +72,62 @@ namespace
namespace AtlasMessage {
MESSAGEHANDLER(GenerateMap)
QUERYHANDLER(GenerateMap)
{
InitGame();
// Load the empty default map
StartGame(L"_default");
// Random map
ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
CScriptValRooted attrs;
scriptInterface.Eval("({})", attrs);
scriptInterface.SetProperty(attrs.get(), "mapType", std::string("random"));
scriptInterface.SetProperty(attrs.get(), "script", std::wstring(*msg->script));
// TODO: use msg->size somehow
// (e.g. load the map then resize the terrain to match it)
UNUSED2(msg);
CScriptValRooted settings;
scriptInterface.Eval("({})", settings);
scriptInterface.SetProperty(settings.get(), "Size", (size_t)msg->size);
scriptInterface.SetProperty(settings.get(), "Seed", (size_t)msg->seed);
scriptInterface.SetProperty(settings.get(), "BaseTerrain", std::vector<std::wstring>(*msg->terrain));
scriptInterface.SetProperty(settings.get(), "BaseHeight", (size_t)msg->height);
scriptInterface.SetProperty(settings.get(), "CircularMap", true); // now default to circular map
CScriptValRooted pData = scriptInterface.ParseJSON(*msg->playerData);
scriptInterface.SetProperty(settings.get(), "PlayerData", pData);
scriptInterface.SetProperty(attrs.get(), "settings", settings, false);
try
{
StartGame(attrs);
msg->status = 0;
}
catch (PSERROR_Game_World_MapLoadFailed e)
{
// Cancel loading
LDR_Cancel();
msg->status = -1;
}
}
MESSAGEHANDLER(LoadMap)
{
InitGame();
StartGame(*msg->filename);
// Scenario
CStrW map = *msg->filename;
CStrW mapBase = map.BeforeLast(L".pmp"); // strip the file extension, if any
ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
CScriptValRooted attrs;
scriptInterface.Eval("({})", attrs);
scriptInterface.SetProperty(attrs.get(), "mapType", std::string("scenario"));
scriptInterface.SetProperty(attrs.get(), "map", std::wstring(mapBase));
StartGame(attrs);
}
MESSAGEHANDLER(SaveMap)
@ -111,4 +141,19 @@ MESSAGEHANDLER(SaveMap)
g_Game->GetSimulation2());
}
QUERYHANDLER(GetMapSettings)
{
msg->settings = g_Game->GetSimulation2()->GetMapSettingsString();
}
MESSAGEHANDLER(SetMapSettings)
{
g_Game->GetSimulation2()->SetMapSettings(*msg->settings);
}
QUERYHANDLER(GetRMSData)
{
msg->data = g_Game->GetSimulation2()->GetRMSData();
}
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -15,13 +15,24 @@
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../Common/Sidebar.h"
#include "precompiled.h"
class TerrainSidebar : public Sidebar
#include "MessageHandler.h"
#include "ps/Game.h"
#include "simulation2/Simulation2.h"
namespace AtlasMessage {
QUERYHANDLER(GetCivData)
{
public:
TerrainSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer);
msg->data = g_Game->GetSimulation2()->GetCivData();
}
protected:
virtual void OnFirstDisplay();
};
QUERYHANDLER(GetPlayerDefaults)
{
msg->defaults = g_Game->GetSimulation2()->GetPlayerDefaults();
}
}

View File

@ -42,10 +42,10 @@ namespace AtlasMessage {
QUERYHANDLER(GetTerrainGroups)
{
const CTerrainTextureManager::TerrainGroupMap &groups = g_TexMan.GetGroups();
std::vector<std::wstring> groupnames;
std::vector<std::wstring> groupNames;
for (CTerrainTextureManager::TerrainGroupMap::const_iterator it = groups.begin(); it != groups.end(); ++it)
groupnames.push_back(it->first.FromUTF8());
msg->groupnames = groupnames;
groupNames.push_back(it->first.FromUTF8());
msg->groupNames = groupNames;
}
static bool CompareTerrain(const sTerrainGroupPreview& a, const sTerrainGroupPreview& b)
@ -57,13 +57,13 @@ QUERYHANDLER(GetTerrainGroupPreviews)
{
std::vector<sTerrainGroupPreview> previews;
CTerrainGroup* group = g_TexMan.FindGroup(CStrW(*msg->groupname).ToUTF8());
CTerrainGroup* group = g_TexMan.FindGroup(CStrW(*msg->groupName).ToUTF8());
for (std::vector<CTerrainTextureEntry*>::const_iterator it = group->GetTerrains().begin(); it != group->GetTerrains().end(); ++it)
{
previews.push_back(sTerrainGroupPreview());
previews.back().name = (*it)->GetTag().FromUTF8();
std::vector<unsigned char> buf (msg->imagewidth*msg->imageheight*3);
std::vector<unsigned char> buf (msg->imageWidth*msg->imageHeight*3);
// It's not good to shrink the entire texture to fit the small preview
// window, since it's the fine details in the texture that are
@ -78,11 +78,11 @@ QUERYHANDLER(GetTerrainGroupPreviews)
glGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_WIDTH, &w);
glGetTexLevelParameteriv(GL_TEXTURE_2D, level, GL_TEXTURE_HEIGHT, &h);
if (w < msg->imagewidth || h < msg->imageheight)
if (w < msg->imageWidth || h < msg->imageHeight)
{
// Oops, too small to preview - just use a flat colour
u32 c = (*it)->GetBaseColor();
for (ssize_t i = 0; i < msg->imagewidth*msg->imageheight; ++i)
for (ssize_t i = 0; i < msg->imageWidth*msg->imageHeight; ++i)
{
buf[i*3+0] = (c>>16) & 0xff;
buf[i*3+1] = (c>>8) & 0xff;
@ -97,12 +97,12 @@ QUERYHANDLER(GetTerrainGroupPreviews)
// Extract the middle section (as a representative preview),
// and copy into buf
unsigned char* texdata_ptr = texdata + (w*(h - msg->imageheight)/2 + (w - msg->imagewidth)/2) * 3;
unsigned char* texdata_ptr = texdata + (w*(h - msg->imageHeight)/2 + (w - msg->imageWidth)/2) * 3;
unsigned char* buf_ptr = &buf[0];
for (ssize_t y = 0; y < msg->imageheight; ++y)
for (ssize_t y = 0; y < msg->imageHeight; ++y)
{
memcpy(buf_ptr, texdata_ptr, msg->imagewidth*3);
buf_ptr += msg->imagewidth*3;
memcpy(buf_ptr, texdata_ptr, msg->imageWidth*3);
buf_ptr += msg->imageWidth*3;
texdata_ptr += w*3;
}
@ -110,9 +110,9 @@ QUERYHANDLER(GetTerrainGroupPreviews)
}
previews.back().loaded = (*it)->GetTexture()->IsLoaded();
previews.back().imagewidth = msg->imagewidth;
previews.back().imageheight = msg->imageheight;
previews.back().imagedata = buf;
previews.back().imageWidth = msg->imageWidth;
previews.back().imageHeight = msg->imageHeight;
previews.back().imageData = buf;
}
// Sort the list alphabetically by name
@ -127,10 +127,10 @@ QUERYHANDLER(GetTerrainPassabilityClasses)
{
std::map<std::string, ICmpPathfinder::pass_class_t> classes = cmpPathfinder->GetPassabilityClasses();
std::vector<std::wstring> classnames;
std::vector<std::wstring> classNames;
for (std::map<std::string, ICmpPathfinder::pass_class_t>::iterator it = classes.begin(); it != classes.end(); ++it)
classnames.push_back(CStr(it->first).FromUTF8());
msg->classnames = classnames;
classNames.push_back(CStr(it->first).FromUTF8());
msg->classNames = classNames;
}
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -130,9 +130,17 @@ MESSAGE(ResizeScreen,
);
//////////////////////////////////////////////////////////////////////////
// Messages for map panel
MESSAGE(GenerateMap,
((int, size)) // size in number of patches
QUERY(GenerateMap,
((std::wstring, script)) // name of script
((size_t, size)) // size in number of patches
((size_t, seed)) // seed for rng
((std::vector<std::wstring>, terrain)) // base terrain(s)
((size_t, height)) // base height
((std::string, playerData)) // JSON player data
,
((int, status)) // Status code, 0 for success, or < 0 for failure
);
MESSAGE(LoadMap,
@ -143,6 +151,33 @@ MESSAGE(SaveMap,
((std::wstring, filename))
);
QUERY(GetMapSettings,
,
((std::string, settings))
);
MESSAGE(SetMapSettings,
((std::string, settings))
);
QUERY(GetRMSData,
,
((std::vector<std::string>, data))
);
//////////////////////////////////////////////////////////////////////////
// Messages for player panel
QUERY(GetCivData,
,
((std::vector<std::string>, data))
);
QUERY(GetPlayerDefaults,
,
((std::string, defaults))
);
//////////////////////////////////////////////////////////////////////////
MESSAGE(RenderStyle,
@ -193,7 +228,7 @@ MESSAGE(BrushPreview,
QUERY(GetTerrainGroups,
, // no inputs
((std::vector<std::wstring>, groupnames))
((std::vector<std::wstring>, groupNames))
);
#ifndef MESSAGES_SKIP_STRUCTS
@ -201,24 +236,24 @@ struct sTerrainGroupPreview
{
Shareable<std::wstring> name;
Shareable<bool> loaded;
Shareable<int> imagewidth;
Shareable<int> imageheight;
Shareable<std::vector<unsigned char> > imagedata; // RGB*width*height
Shareable<int> imageWidth;
Shareable<int> imageHeight;
Shareable<std::vector<unsigned char> > imageData; // RGB*width*height
};
SHAREABLE_STRUCT(sTerrainGroupPreview);
#endif
QUERY(GetTerrainGroupPreviews,
((std::wstring, groupname))
((int, imagewidth))
((int, imageheight))
((std::wstring, groupName))
((int, imageWidth))
((int, imageHeight))
,
((std::vector<sTerrainGroupPreview>, previews))
);
QUERY(GetTerrainPassabilityClasses,
, // no inputs
((std::vector<std::wstring>, classnames))
((std::vector<std::wstring>, classNames))
);
//////////////////////////////////////////////////////////////////////////
@ -247,7 +282,7 @@ struct sObjectSettings
// Some settings are immutable and therefore are ignored (and should be left
// empty) when passed from the editor to the game:
Shareable<std::vector<std::vector<std::wstring> > > variantgroups;
Shareable<std::vector<std::vector<std::wstring> > > variantGroups;
};
SHAREABLE_STRUCT(sObjectSettings);
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -35,7 +35,6 @@
#include "ps/GameSetup/GameSetup.h"
#include "ps/World.h"
#include "renderer/Renderer.h"
#include "simulation/Simulation.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpObstructionManager.h"
#include "simulation2/components/ICmpPathfinder.h"