forked from mirrors/0ad
Add new Keywords tag to maps. Add map list filtering API to game setup. Add some default filters that use map keywords. Cleaned up client game setup a bit. Removed deprecated GUI utility functions.
This was SVN commit r8800.
This commit is contained in:
@@ -17,61 +17,32 @@ function getRandom(randomMin, randomMax)
|
||||
|
||||
// ====================================================================
|
||||
|
||||
function parseDelimiterString (parseString, delimiter)
|
||||
{
|
||||
// Seeks through the delimiters in a string and populates the elements of an array with fields found between them.
|
||||
|
||||
// Declare local variables.
|
||||
var parseLoop = 0;
|
||||
var parseElement = 0;
|
||||
var seekDelimiter = 0;
|
||||
var parseArray = new Array();
|
||||
|
||||
// While we're still within the bounds of the string,
|
||||
while (parseLoop <= parseString.length)
|
||||
{
|
||||
// Seek until we find a delimiter.
|
||||
seekDelimiter = parseLoop;
|
||||
while (parseString[seekDelimiter] != delimiter && seekDelimiter <= parseString.length)
|
||||
seekDelimiter++;
|
||||
|
||||
// If we found a delimiter within the string,
|
||||
if (seekDelimiter != parseString.length)
|
||||
{
|
||||
// Store sub-string between start point and delimiter in array element.
|
||||
parseArray[parseElement] = parseString.substring(parseLoop, seekDelimiter);
|
||||
parseElement++;
|
||||
}
|
||||
|
||||
// Move to after delimiter position for next seek.
|
||||
parseLoop = seekDelimiter+1;
|
||||
}
|
||||
|
||||
// Store length of array.
|
||||
parseArray.length = parseElement;
|
||||
|
||||
return parseArray;
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
|
||||
// Get list of XML files in pathname excepting those starting with _
|
||||
// Get list of XML files in pathname with recursion, excepting those starting with _
|
||||
function getXMLFileList(pathname)
|
||||
{
|
||||
var files = buildDirEntList(pathname, "*.xml", false);
|
||||
var files = buildDirEntList(pathname, "*.xml", true);
|
||||
|
||||
// Remove the path and extension from each name, since we just want the filename
|
||||
files = [ n.substring(pathname.length, n.length-4) for each (n in files) ];
|
||||
var result = [];
|
||||
|
||||
// Get only subpath from filename and discard extension
|
||||
for (var i = 0; i < files.length; ++i)
|
||||
{
|
||||
var file = files[i];
|
||||
file = file.substring(pathname.length, file.length-4);
|
||||
|
||||
// Remove any files starting with "_" (these are for special maps used by the engine/editor)
|
||||
files = [ n for each (n in files) if (n[0] != "_") ];
|
||||
// Split path into directories so we can check for beginning _ character
|
||||
var tokens = file.split("/");
|
||||
|
||||
if (tokens[tokens.length-1][0] != "_")
|
||||
result.push(file);
|
||||
}
|
||||
|
||||
return files;
|
||||
return result;
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
|
||||
// Get list of JSON files in pathname excepting those starting with _
|
||||
// Get list of JSON files in pathname
|
||||
function getJSONFileList(pathname)
|
||||
{
|
||||
var files = buildDirEntList(pathname, "*.json", false);
|
||||
@@ -79,9 +50,6 @@ function getJSONFileList(pathname)
|
||||
// Remove the path and extension from each name, since we just want the filename
|
||||
files = [ n.substring(pathname.length, n.length-5) for each (n in files) ];
|
||||
|
||||
// Remove any files starting with "_" (these are for special maps used by the engine/editor)
|
||||
files = [ n for each (n in files) if (n[0] != "_") ];
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
@@ -152,18 +120,6 @@ function escapeText(text)
|
||||
|
||||
// ====================================================================
|
||||
|
||||
function addArrayElement(Array)
|
||||
{
|
||||
// Adds an element to an array, updates its given index, and returns the index of the element.
|
||||
|
||||
Array[Array.last] = new Object();
|
||||
Array.last++;
|
||||
|
||||
return (Array.last - 1);
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
|
||||
function toTitleCase (string)
|
||||
{
|
||||
if (!string)
|
||||
|
||||
@@ -42,6 +42,8 @@ var g_ChatMessages = [];
|
||||
var g_MapData = {};
|
||||
var g_CivData = {};
|
||||
|
||||
var g_MapFilters = [];
|
||||
|
||||
|
||||
function init(attribs)
|
||||
{
|
||||
@@ -78,6 +80,18 @@ function init(attribs)
|
||||
mapTypes.list = ["Scenario"]; // TODO: May offer saved game type for multiplayer games?
|
||||
mapTypes.list_data = ["scenario"];
|
||||
|
||||
// Setup map filters - will appear in order they are added
|
||||
addFilter("Default", function(settings) { return settings && !keywordTestOR(settings.Keywords, ["demo", "test"]); });
|
||||
addFilter("Demo Maps", function(settings) { return settings && keywordTestAND(settings.Keywords, ["demo"]); });
|
||||
addFilter("Test Maps", function(settings) { return settings && keywordTestAND(settings.Keywords, ["test"]); });
|
||||
addFilter("Old Maps", function(settings) { return !settings; });
|
||||
addFilter("All Maps", function(settings) { return true; });
|
||||
|
||||
//Populate map filters dropdown
|
||||
var mapFilters = getGUIObjectByName("mapFilterSelection");
|
||||
mapFilters.list = getFilters();
|
||||
g_GameAttributes.mapFilter = "Default";
|
||||
|
||||
// Setup controls for host only
|
||||
if (g_IsController)
|
||||
{
|
||||
@@ -89,6 +103,7 @@ function init(attribs)
|
||||
g_GameAttributes.map = "Gold_Rush";
|
||||
|
||||
mapTypes.selected = 0;
|
||||
mapFilters.selected = 0;
|
||||
|
||||
initMapNameList();
|
||||
|
||||
@@ -146,7 +161,8 @@ function init(attribs)
|
||||
{
|
||||
// If we're a network client, disable all the map controls
|
||||
// TODO: make them look visually disabled so it's obvious why they don't work
|
||||
getGUIObjectByName("mapTypeSelection").enabled = false;
|
||||
getGUIObjectByName("mapTypeSelection").hidden = true;
|
||||
getGUIObjectByName("mapFilterSelection").hidden = true;
|
||||
getGUIObjectByName("mapSelection").enabled = false;
|
||||
|
||||
// Disable player and game options controls
|
||||
@@ -359,12 +375,17 @@ function initMapNameList()
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache map data
|
||||
for (var file in mapFiles)
|
||||
loadMapData(mapFiles[file]);
|
||||
|
||||
var mapList = [ { "name": getMapDisplayName(file), "file": file } for each (file in mapFiles) ];
|
||||
|
||||
// Apply map filter, if any defined
|
||||
var mapList = [];
|
||||
for (var i = 0; i < mapFiles.length; ++i)
|
||||
{
|
||||
var file = mapFiles[i];
|
||||
var mapData = loadMapData(file);
|
||||
|
||||
if (g_GameAttributes.mapFilter && mapData && testFilter(g_GameAttributes.mapFilter, mapData.settings))
|
||||
mapList.push({ "name": getMapDisplayName(file), "file": file });
|
||||
}
|
||||
|
||||
// Alphabetically sort the list, ignoring case
|
||||
mapList.sort(sortNameIgnoreCase);
|
||||
|
||||
@@ -373,8 +394,8 @@ function initMapNameList()
|
||||
|
||||
// Select the default map
|
||||
var selected = mapListFiles.indexOf(g_GameAttributes.map);
|
||||
// Default to the first element if we can't find the one we searched for
|
||||
if (selected == -1)
|
||||
// Default to the first element if list is not empty and we can't find the one we searched for
|
||||
if (selected == -1 && mapList.length)
|
||||
selected = 0;
|
||||
|
||||
// Update the list control
|
||||
@@ -385,6 +406,9 @@ function initMapNameList()
|
||||
|
||||
function loadMapData(name)
|
||||
{
|
||||
if (!name)
|
||||
return undefined;
|
||||
|
||||
if (!g_MapData[name])
|
||||
{
|
||||
switch (g_GameAttributes.mapType)
|
||||
@@ -469,6 +493,26 @@ function selectMapType(type)
|
||||
onGameAttributesChange();
|
||||
}
|
||||
|
||||
function selectMapFilter(filterName)
|
||||
{
|
||||
// Avoid recursion
|
||||
if (g_IsInGuiUpdate)
|
||||
return;
|
||||
|
||||
// Network clients can't change map filter
|
||||
if (g_IsNetworked && !g_IsController)
|
||||
return;
|
||||
|
||||
g_GameAttributes.mapFilter = filterName;
|
||||
|
||||
initMapNameList();
|
||||
|
||||
if (g_IsNetworked)
|
||||
Engine.SetNetworkGameAttributes(g_GameAttributes);
|
||||
else
|
||||
onGameAttributesChange();
|
||||
}
|
||||
|
||||
// Called when the user selects a map from the list
|
||||
function selectMap(name)
|
||||
{
|
||||
@@ -479,6 +523,10 @@ function selectMap(name)
|
||||
// Network clients can't change map
|
||||
if (g_IsNetworked && !g_IsController)
|
||||
return;
|
||||
|
||||
// Return if we have no map
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
g_GameAttributes.map = name;
|
||||
|
||||
@@ -543,12 +591,14 @@ function onGameAttributesChange()
|
||||
// Update some controls for clients
|
||||
if (!g_IsController)
|
||||
{
|
||||
var mapTypeSelectionBox = getGUIObjectByName("mapTypeSelection");
|
||||
var mapTypeIdx = mapTypeSelectionBox.list_data.indexOf(g_GameAttributes.mapType);
|
||||
mapTypeSelectionBox.selected = mapTypeIdx;
|
||||
var mapFilterHeading = getGUIObjectByName("mapFilterHeading");
|
||||
mapFilterHeading.caption = "Map Filter: "+g_GameAttributes.mapFilter;
|
||||
var mapTypeSelection = getGUIObjectByName("mapTypeSelection");
|
||||
var mapTypeHeading = getGUIObjectByName("mapTypeHeading");
|
||||
var idx = mapTypeSelection.list_data.indexOf(g_GameAttributes.mapType);
|
||||
mapTypeHeading.caption = "Match Type: "+mapTypeSelection.list[idx];
|
||||
var mapSelectionBox = getGUIObjectByName("mapSelection");
|
||||
var mapIdx = mapSelectionBox.list_data.indexOf(mapName);
|
||||
mapSelectionBox.selected = mapIdx;
|
||||
mapSelectionBox.selected = mapSelectionBox.list_data.indexOf(mapName);
|
||||
|
||||
initMapNameList();
|
||||
|
||||
@@ -577,6 +627,7 @@ function onGameAttributesChange()
|
||||
// Show options for host/controller
|
||||
if (g_IsController)
|
||||
{
|
||||
getGUIObjectByName("numPlayersSelection").selected = g_NumPlayers - 1;
|
||||
numPlayersBox.hidden = false;
|
||||
mapSize.hidden = false;
|
||||
revealMap.hidden = false;
|
||||
@@ -836,3 +887,78 @@ function addChatMessage(msg)
|
||||
|
||||
getGUIObjectByName("chatText").caption = g_ChatMessages.join("\n");
|
||||
}
|
||||
|
||||
|
||||
// Basic map filters API
|
||||
|
||||
// Add a new map list filter
|
||||
function addFilter(name, filterFunc)
|
||||
{
|
||||
if (filterFunc instanceof Object)
|
||||
{ // Basic validity test
|
||||
var newFilter = {};
|
||||
newFilter.name = name;
|
||||
newFilter.filter = filterFunc;
|
||||
|
||||
g_MapFilters.push(newFilter);
|
||||
}
|
||||
else
|
||||
{
|
||||
error("Invalid map filter: "+name);
|
||||
}
|
||||
}
|
||||
|
||||
// Get array of map filter names
|
||||
function getFilters()
|
||||
{
|
||||
var filters = [];
|
||||
for (var i = 0; i < g_MapFilters.length; ++i)
|
||||
{
|
||||
filters.push(g_MapFilters[i].name);
|
||||
}
|
||||
|
||||
return filters;
|
||||
}
|
||||
|
||||
// Test map filter on given map settings object
|
||||
function testFilter(name, mapSettings)
|
||||
{
|
||||
for (var i = 0; i < g_MapFilters.length; ++i)
|
||||
{
|
||||
if (g_MapFilters[i].name == name)
|
||||
{ // Found filter
|
||||
return g_MapFilters[i].filter(mapSettings);
|
||||
}
|
||||
}
|
||||
|
||||
error("Invalid map filter: "+name);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test an array of keywords against a match array using AND logic
|
||||
function keywordTestAND(keywords, matches)
|
||||
{
|
||||
if (!keywords || !matches)
|
||||
return false;
|
||||
|
||||
for (var m = 0; m < matches.length; ++m)
|
||||
{ // Fail on not match
|
||||
if (keywords.indexOf(matches[m]) == -1)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test an array of keywords against a match array using OR logic
|
||||
function keywordTestOR(keywords, matches)
|
||||
{
|
||||
if (!keywords || !matches)
|
||||
return false;
|
||||
|
||||
for (var m = 0; m < matches.length; ++m)
|
||||
{ // Success on match
|
||||
if (keywords.indexOf(matches[m]) != -1)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -29,8 +29,7 @@
|
||||
<!-- Map selection -->
|
||||
|
||||
<object size="0 0 250 100%">
|
||||
<object name="mapSelectionHeading" type="text" text_valign="center" size="0 0 100% 30" font="serif-bold-16">Match Type</object>
|
||||
|
||||
<object name="mapTypeHeading" type="text" text_valign="center" size="0 0 100% 30" font="serif-bold-16">Match Type:</object>
|
||||
<object name="mapTypeSelection"
|
||||
type="dropdown"
|
||||
style="wheatDropDown"
|
||||
@@ -39,19 +38,29 @@
|
||||
tooltip="Select a map type.">
|
||||
<action on="SelectionChange">selectMapType(this.list_data[this.selected]);</action>
|
||||
</object>
|
||||
|
||||
<object name="mapFilterHeading" type="text" text_valign="center" size="0 34 100% 64" font="serif-bold-14">Map Filter:</object>
|
||||
<object name="mapFilterSelection"
|
||||
type="dropdown"
|
||||
style="wheatDropDown"
|
||||
size="100 34 100% 64"
|
||||
tooltip_style="onscreenToolTip"
|
||||
tooltip="Select a map filter.">
|
||||
<action on="SelectionChange">selectMapFilter(this.list[this.selected]);</action>
|
||||
</object>
|
||||
|
||||
<object name="mapSelection"
|
||||
style="wheatList"
|
||||
type="list"
|
||||
size="0 36 100% 100%-200"
|
||||
size="0 70 100% 100%-200"
|
||||
tooltip_style="onscreenToolTip"
|
||||
tooltip="Select a map to play on.">
|
||||
<action on="SelectionChange">selectMap(this.list_data[this.selected]);</action>
|
||||
</object>
|
||||
|
||||
<object type="image" style="indentedPanel" size="0 100%-190 100% 100%">
|
||||
<object name="mapInfoName" type="text" size="0 0 100% 30" font="serif-bold-18">[Map name]</object>
|
||||
<object name="mapInfoDescription" type="text" size="0 24 100% 100%" font="serif-13">[Description]</object>
|
||||
<object name="mapInfoName" type="text" size="0 0 100% 30" font="serif-bold-18"/>
|
||||
<object name="mapInfoDescription" type="text" size="0 24 100% 100%" font="serif-13"/>
|
||||
</object>
|
||||
|
||||
</object>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user