Ticket #1834: gamesetup_playerCapsForRms.diff
File gamesetup_playerCapsForRms.diff, 36.4 KB (added by , 11 years ago) |
---|
-
binaries/data/mods/public/gui/gamesetup/gamesetup.js
15 15 const STARTING_RESOURCES_DEFAULTIDX = 1; 16 16 // Max number of players for any map 17 17 const MAX_PLAYERS = 8; 18 // The default upper player limit for random maps by map size: 19 // [Tiny, Small, Medium, Normal, Large, Very Large, Giant] 20 // Ignored if explicitely defined in the RMS json 21 // Still capped at MAX_PLAYERS if excessing it in getPlayersCapRMS(). 22 const MAX_PLAYERS_BY_MAP_SIZE_RMS = [4, 6, 8, 8, 8, 8, 8]; 23 // The default upper player limit for random maps 24 // Ignored if explicitely defined in the RMS json 25 const MIN_PLAYERS_RMS = 1; 26 // The default number of player for random maps 27 const DEFAULT_NUM_PLAYERS_RMS = 2; 18 28 19 29 //////////////////////////////////////////////////////////////////////////////////////////////// 20 30 … … 86 96 { 87 97 // Load AI list and hide deprecated AIs 88 98 g_AIs = Engine.GetAIs(); 89 99 90 100 // Sort AIs by displayed name 91 101 g_AIs.sort(function (a, b) { 92 102 return a.data.name < b.data.name ? -1 : b.data.name < a.data.name ? +1 : 0; 93 103 }); 94 104 95 105 // Get default player data - remove gaia 96 106 g_DefaultPlayerData = initPlayerDefaults(); 97 107 g_DefaultPlayerData.shift(); … … 99 109 g_DefaultPlayerData[i].Civ = "random"; 100 110 101 111 g_MapSizes = initMapSizes(); 102 112 103 113 // Init civs 104 114 initCivNameList(); 105 115 106 116 // Init map types 107 117 var mapTypes = getGUIObjectByName("mapTypeSelection"); 108 118 mapTypes.list = ["Scenario","Random"]; 109 119 mapTypes.list_data = ["scenario","random"]; 110 120 111 121 // Setup map filters - will appear in order they are added 112 122 addFilter("Default", function(settings) { return settings && !keywordTestOR(settings.Keywords, ["naval", "demo", "hidden"]); }); 113 123 addFilter("Naval Maps", function(settings) { return settings && keywordTestAND(settings.Keywords, ["naval"]); }); 114 124 addFilter("Demo Maps", function(settings) { return settings && keywordTestAND(settings.Keywords, ["demo"]); }); 115 125 addFilter("Old Maps", function(settings) { return !settings; }); 116 126 addFilter("All Maps", function(settings) { return true; }); 117 127 118 128 // Populate map filters dropdown 119 129 var mapFilters = getGUIObjectByName("mapFilterSelection"); 120 130 mapFilters.list = getFilters(); 121 131 g_GameAttributes.mapFilter = "Default"; 122 132 123 133 // Setup controls for host only 124 134 if (g_IsController) 125 135 { 126 136 mapTypes.selected = 0; 127 137 mapFilters.selected = 0; 128 138 129 139 initMapNameList(); 130 140 131 141 var numPlayersSelection = getGUIObjectByName("numPlayersSelection"); 132 142 var players = []; 133 143 for (var i = 1; i <= MAX_PLAYERS; ++i) 134 144 players.push(i); 135 145 numPlayersSelection.list = players; 136 146 numPlayersSelection.list_data = players; 137 numPlayersSelection.selected = MAX_PLAYERS - 1;138 147 numPlayersSelection.selected = DEFAULT_NUM_PLAYERS_RMS - players[0]; 148 139 149 var populationCaps = getGUIObjectByName("populationCap"); 140 150 populationCaps.list = POPULATION_CAP; 141 151 populationCaps.list_data = POPULATION_CAP_DATA; … … 179 189 { 180 190 g_GameAttributes.settings.GameType = VICTORY_DATA[this.selected]; 181 191 } 182 192 183 193 if (!g_IsInGuiUpdate) 184 194 { 185 195 updateGameAttributes(); 186 196 } 187 197 }; 188 198 victoryConditions.selected = VICTORY_DEFAULTIDX; 189 199 190 200 var mapSize = getGUIObjectByName("mapSize"); 191 201 mapSize.list = g_MapSizes.names; 192 202 mapSize.list_data = g_MapSizes.tiles; … … 196 206 { 197 207 g_GameAttributes.settings.Size = g_MapSizes.tiles[this.selected]; 198 208 } 199 209 changeNumPlayersCaps(); 210 200 211 if (!g_IsInGuiUpdate) 201 212 { 202 213 updateGameAttributes(); 203 214 } 204 215 }; 205 216 206 217 getGUIObjectByName("revealMap").onPress = function() 207 218 { // Update attributes so other players can see change 208 219 g_GameAttributes.settings.RevealMap = this.checked; 209 220 210 221 if (!g_IsInGuiUpdate) 211 222 { 212 223 updateGameAttributes(); 213 224 } 214 225 }; 215 226 216 227 getGUIObjectByName("lockTeams").onPress = function() 217 228 { // Update attributes so other players can see change 218 229 g_GameAttributes.settings.LockTeams = this.checked; 219 230 220 231 if (!g_IsInGuiUpdate) 221 232 { 222 233 updateGameAttributes(); … … 226 237 getGUIObjectByName("enableCheats").onPress = function() 227 238 { // Update attributes so other players can see change 228 239 g_GameAttributes.settings.CheatsEnabled = this.checked; 229 240 230 241 if (!g_IsInGuiUpdate) 231 242 { 232 243 updateGameAttributes(); … … 254 265 getGUIObjectByName("playerCiv["+i+"]").hidden = true; 255 266 getGUIObjectByName("playerTeam["+i+"]").hidden = true; 256 267 } 257 268 258 269 getGUIObjectByName("numPlayersSelection").hidden = true; 259 270 } 260 271 261 272 // Set up multiplayer/singleplayer bits: 262 273 if (!g_IsNetworked) 263 274 { … … 279 290 getGUIObjectByName("enableCheatsText").hidden = false; 280 291 } 281 292 } 282 293 283 294 // Settings for all possible player slots 284 295 var boxSpacing = 32; 285 296 for (var i = 0; i < MAX_PLAYERS; ++i) … … 291 302 boxSize.top = i * boxSpacing; 292 303 boxSize.bottom = i * boxSpacing + h; 293 304 box.size = boxSize; 294 305 295 306 // Populate team dropdowns 296 307 var team = getGUIObjectByName("playerTeam["+i+"]"); 297 308 team.list = ["None", "1", "2", "3", "4"]; 298 309 team.list_data = [-1, 0, 1, 2, 3]; 299 310 team.selected = 0; 300 311 301 312 let playerSlot = i; // declare for inner function use 302 313 team.onSelectionChange = function() 303 314 { // Update team … … 305 316 { 306 317 g_GameAttributes.settings.PlayerData[playerSlot].Team = this.selected - 1; 307 318 } 308 319 309 320 if (!g_IsInGuiUpdate) 310 321 { 311 322 updateGameAttributes(); 312 323 } 313 324 }; 314 325 315 326 316 327 // Set events 317 328 var civ = getGUIObjectByName("playerCiv["+i+"]"); 318 329 civ.onSelectionChange = function() … … 321 332 { 322 333 g_GameAttributes.settings.PlayerData[playerSlot].Civ = this.list_data[this.selected]; 323 334 } 324 335 325 336 if (!g_IsInGuiUpdate) 326 337 { 327 338 updateGameAttributes(); 328 339 } 329 340 }; 330 341 } 331 342 332 343 if (g_IsNetworked) 333 344 { 334 345 // For multiplayer, focus the chat input box by default … … 345 356 function handleNetMessage(message) 346 357 { 347 358 log("Net message: "+uneval(message)); 348 359 349 360 switch (message.type) 350 361 { 351 362 case "netstatus": … … 356 367 Engine.PopGuiPage(); 357 368 reportDisconnect(message.reason); 358 369 break; 359 370 360 371 default: 361 372 error("Unrecognised netstatus type "+message.status); 362 373 break; 363 374 } 364 375 break; 365 376 366 377 case "gamesetup": 367 378 if (message.data) // (the host gets undefined data on first connect, so skip that) 368 379 { … … 371 382 372 383 onGameAttributesChange(); 373 384 break; 374 385 375 386 case "players": 376 387 // Find and report all joinings/leavings 377 388 for (var host in message.hosts) … … 392 403 g_PlayerAssignments = message.hosts; 393 404 updatePlayerList(); 394 405 break; 395 406 396 407 case "start": 397 408 Engine.SwitchGuiPage("page_loading.xml", { 398 409 "attribs": g_GameAttributes, … … 400 411 "playerAssignments": g_PlayerAssignments 401 412 }); 402 413 break; 403 414 404 415 case "chat": 405 416 addChatMessage({ "type": "message", "guid": message.guid, "text": message.text }); 406 417 break; 407 418 408 419 default: 409 420 error("Unrecognised net message type "+message.type); 410 421 } … … 414 425 function getMapDisplayName(map) 415 426 { 416 427 var mapData = loadMapData(map); 417 428 418 429 if (!mapData || !mapData.settings || !mapData.settings.Name) 419 430 { // Give some msg that map format is unsupported 420 431 log("Map data missing in scenario '"+map+"' - likely unsupported format"); 421 432 return map; 422 433 } 423 434 424 435 return mapData.settings.Name; 425 436 } 426 437 … … 428 439 function getMapPreview(map) 429 440 { 430 441 var mapData = loadMapData(map); 431 442 432 443 if (!mapData || !mapData.settings || !mapData.settings.Preview) 433 444 { // Give some msg that map format is unsupported 434 445 return "nopreview.png"; 435 446 } 436 447 437 448 return mapData.settings.Preview; 438 449 } 439 450 … … 444 455 { 445 456 return settings[property]; 446 457 } 447 458 448 459 // Use defaults 449 460 if (defaults && (property in defaults)) 450 461 { 451 462 return defaults[property]; 452 463 } 453 464 454 465 return undefined; 455 466 } 456 467 468 // Get the possible number of players for this random map ny map size 469 function getPlayersCapRMS(mapName, mapSize, maxPlayersByMapSizeRMS, minPlayersRMS) 470 { 471 // Get map name 472 mapName = (mapName || g_GameAttributes.map); 473 // Get map size 474 if (mapSize || g_GameAttributes.settings.Size) 475 mapSize = (mapSize || g_GameAttributes.settings.Size); 476 else 477 { 478 // Only a log to not show up at gui initialization 479 log("getPlayersCapRMS: g_GameAttributes.settings.Size is undefined! Returning MAX_PLAYERS = " + MAX_PLAYERS); 480 return {"min" : MIN_PLAYERS_RMS, "max" : MAX_PLAYERS}; 481 } 482 // Get maximum numbers of players by map size array 483 if (g_MapData[mapName] && g_MapData[mapName].settings && g_MapData[mapName].settings.MaximumPlayersByMapSize) 484 maxPlayersByMapSizeRMS = (maxPlayersByMapSizeRMS || g_MapData[mapName].settings.MaximumPlayersByMapSize); 485 else 486 maxPlayersByMapSizeRMS = (maxPlayersByMapSizeRMS || MAX_PLAYERS_BY_MAP_SIZE_RMS); 487 488 // Get minimum numbers of players by map size 489 if (g_MapData[mapName] && g_MapData[mapName].settings && g_MapData[mapName].settings.MinimumPlayers) 490 minPlayersRMS = (minPlayersRMS || g_MapData[mapName].settings.MinimumPlayers); 491 else 492 minPlayersRMS = (minPlayersRMS || MIN_PLAYERS_RMS); 493 494 // Setting upper player cap 495 var maxPlayers = Math.min(maxPlayersByMapSizeRMS[Math.round(mapSize/64 - 2)], MAX_PLAYERS); 496 if (maxPlayers < 2) 497 { 498 warn("getPlayersCapRMS: Maximum number of players should at least be 2 but is " + maxPlayers + "! Setting it to 2."); 499 maxPlayers = 2; 500 } 501 502 // Setting lower players cap 503 var minPlayers = minPlayersRMS; 504 if (minPlayers > maxPlayers) 505 { 506 warn("getPlayersCapRMS: minPlayers > maxPlayers! Lowering minPlayers (" + minPlayers + ") to maxPlayers (" + maxPlayers + ")."); 507 minPlayers = maxPlayers; 508 } 509 510 return {"min" : minPlayers, "max" : maxPlayers}; 511 } 512 513 // Change player number combobox content and update number of players combobox 514 function changeNumPlayersCaps(playerCaps) 515 { 516 playerCaps = (playerCaps || getPlayersCapRMS()); 517 var numPlayersSelection = getGUIObjectByName("numPlayersSelection"); 518 var selectedNumPlayers = parseInt(numPlayersSelection.list_data[numPlayersSelection.selected]); 519 var pList = []; 520 for (var i = playerCaps.min; i <= playerCaps.max; ++i) 521 pList.push(i); 522 numPlayersSelection.list = pList; 523 numPlayersSelection.list_data = pList; 524 if (!selectedNumPlayers) 525 { 526 if (pList.indexOf(DEFAULT_NUM_PLAYERS_RMS) !== -1) 527 numPlayersSelection.selected = pList.indexOf(DEFAULT_NUM_PLAYERS_RMS); 528 else if (DEFAULT_NUM_PLAYERS_RMS > pList[pList.length - 1]) 529 numPlayersSelection.selected = pList.length - 1; 530 else 531 numPlayersSelection.selected = 0; 532 } 533 else if (pList.indexOf(selectedNumPlayers) !== -1) 534 numPlayersSelection.selected = pList.indexOf(selectedNumPlayers); 535 else if (selectedNumPlayers < pList[0]) 536 numPlayersSelection.selected = 0; 537 else if (selectedNumPlayers > pList[pList.length - 1]) 538 numPlayersSelection.selected = pList.length - 1; 539 else 540 warn("changeNumPlayersCaps: Selected number of players could not be set properly on player cap change!"); 541 selectNumPlayers(pList[numPlayersSelection.selected]); 542 } 543 457 544 // Initialize the dropdowns containing all the available civs 458 545 function initCivNameList() 459 546 { … … 470 557 471 558 // Alphabetically sort the list, ignoring case 472 559 civList.sort(sortNameIgnoreCase); 473 560 474 561 var civListNames = [ civ.name for each (civ in civList) ]; 475 562 var civListCodes = [ civ.code for each (civ in civList) ]; 476 563 477 564 // Add random civ to beginning of list 478 565 civListNames.unshift("[color=\"orange\"]Random"); 479 566 civListCodes.unshift("random"); … … 495 582 // TODO: Should verify these are valid maps before adding to list 496 583 var mapSelectionBox = getGUIObjectByName("mapSelection") 497 584 var mapFiles; 498 585 499 586 switch (g_GameAttributes.mapType) 500 587 { 501 588 case "scenario": 502 589 mapFiles = getXMLFileList(g_GameAttributes.mapPath); 503 590 break; 504 591 505 592 case "random": 506 593 mapFiles = getJSONFileList(g_GameAttributes.mapPath); 507 594 break; 508 595 509 596 default: 510 597 error("initMapNameList: Unexpected map type '"+g_GameAttributes.mapType+"'"); 511 598 return; 512 599 } 513 600 514 601 // Apply map filter, if any defined 515 602 var mapList = []; 516 603 for (var i = 0; i < mapFiles.length; ++i) … … 523 610 mapList.push({ "name": getMapDisplayName(file), "file": file }); 524 611 } 525 612 } 526 613 527 614 // Alphabetically sort the list, ignoring case 528 615 mapList.sort(sortNameIgnoreCase); 529 616 if (g_GameAttributes.mapType == "random") … … 531 618 532 619 var mapListNames = [ map.name for each (map in mapList) ]; 533 620 var mapListFiles = [ map.file for each (map in mapList) ]; 534 621 535 622 // Select the default map 536 623 var selected = mapListFiles.indexOf(g_GameAttributes.map); 537 624 // Default to the first element if list is not empty and we can't find the one we searched for … … 539 626 { 540 627 selected = 0; 541 628 } 542 629 543 630 // Update the list control 544 631 mapSelectionBox.list = mapListNames; 545 632 mapSelectionBox.list_data = mapListFiles; … … 558 645 g_MapData[name] = {settings : {"Name" : "Random", "Description" : "Randomly selects a map from the list"}}; 559 646 return g_MapData[name]; 560 647 } 561 648 562 649 if (!g_MapData[name]) 563 650 { 564 651 switch (g_GameAttributes.mapType) … … 566 653 case "scenario": 567 654 g_MapData[name] = Engine.LoadMapSettings(g_GameAttributes.mapPath+name); 568 655 break; 569 656 570 657 case "random": 571 658 g_MapData[name] = parseJSONData(g_GameAttributes.mapPath+name+".json"); 572 659 break; 573 660 574 661 default: 575 662 error("loadMapData: Unexpected map type '"+g_GameAttributes.mapType+"'"); 576 663 return undefined; 577 664 } 578 665 } 579 666 580 667 return g_MapData[name]; 581 668 } 582 669 … … 624 711 { 625 712 return; 626 713 } 627 714 628 715 // Network clients can't change number of players 629 716 if (g_IsNetworked && !g_IsController) 630 717 { 631 718 return; 632 719 } 633 720 634 721 // Only meaningful for random maps 635 722 if (g_GameAttributes.mapType != "random") 636 723 { 637 724 return; 638 725 } 639 726 640 727 // Update player data 641 728 var pData = g_GameAttributes.settings.PlayerData; 642 729 if (pData && num < pData.length) … … 652 739 g_GameAttributes.settings.PlayerData.push(g_DefaultPlayerData[i]); 653 740 } 654 741 } 655 742 656 743 // Some players may have lost their assigned slot 657 744 for (var guid in g_PlayerAssignments) 658 745 { … … 665 752 g_PlayerAssignments = { "local": { "name": "You", "player": 1, "civ": "", "team": -1} }; 666 753 } 667 754 } 668 755 669 756 updateGameAttributes(); 670 757 } 671 758 … … 677 764 { 678 765 return; 679 766 } 680 767 681 768 // Network clients can't change map type 682 769 if (g_IsNetworked && !g_IsController) 683 770 { 684 771 return; 685 772 } 686 773 687 774 // Reset game attributes 688 775 g_GameAttributes.map = ""; 689 776 g_GameAttributes.mapType = type; 690 777 691 778 // Clear old map data 692 779 g_MapData = {}; 693 780 694 781 // Select correct path 695 782 switch (g_GameAttributes.mapType) 696 783 { … … 700 787 g_GameAttributes.map = (g_IsNetworked ? DEFAULT_NETWORKED_MAP : DEFAULT_OFFLINE_MAP); 701 788 g_GameAttributes.mapPath = "maps/scenarios/"; 702 789 break; 703 790 704 791 case "random": 792 var playerCaps = getPlayersCapRMS(); 705 793 g_GameAttributes.mapPath = "maps/random/"; 706 794 g_GameAttributes.settings = { 707 PlayerData: g_DefaultPlayerData.slice(0, 4),795 PlayerData: g_DefaultPlayerData.slice(0, Math.max(Math.min(DEFAULT_NUM_PLAYERS_RMS, playerCaps.max), playerCaps.min)), 708 796 Seed: Math.floor(Math.random() * 65536), 709 797 CheatsEnabled: g_GameAttributes.settings.CheatsEnabled 710 798 }; 711 799 break; 712 800 713 801 default: 714 802 error("selectMapType: Unexpected map type '"+g_GameAttributes.mapType+"'"); 715 803 return; 716 804 } 717 805 718 806 initMapNameList(); 719 807 720 808 updateGameAttributes(); 809 810 changeNumPlayersCaps(); 721 811 } 722 812 723 813 function selectMapFilter(filterName) … … 727 817 { 728 818 return; 729 819 } 730 820 731 821 // Network clients can't change map filter 732 822 if (g_IsNetworked && !g_IsController) 733 823 { 734 824 return; 735 825 } 736 826 737 827 g_GameAttributes.mapFilter = filterName; 738 828 739 829 initMapNameList(); 740 830 741 831 updateGameAttributes(); 742 832 } 743 833 … … 749 839 { 750 840 return; 751 841 } 752 842 753 843 // Network clients can't change map 754 844 if (g_IsNetworked && !g_IsController) 755 845 { 756 846 return; 757 847 } 758 848 759 849 // Return if we have no map 760 850 if (!name) 761 851 { 762 852 return; 763 853 } 764 854 765 855 var mapData = loadMapData(name); 766 856 var mapSettings = (mapData && mapData.settings ? deepcopy(mapData.settings) : {}); 767 857 768 858 // Copy any new settings 769 859 g_GameAttributes.map = name; 770 860 g_GameAttributes.script = mapSettings.Script; … … 800 890 } 801 891 } 802 892 } 803 893 804 894 updateGameAttributes(); 895 896 changeNumPlayersCaps(); 805 897 } 806 898 807 899 function launchGame() … … 811 903 error("Only host can start game"); 812 904 return; 813 905 } 814 906 815 907 // Check that we have a map 816 908 if (!g_GameAttributes.map) 817 909 { … … 821 913 if (g_GameAttributes.map == "random") 822 914 selectMap(getGUIObjectByName("mapSelection").list_data[Math.floor(Math.random() * 823 915 (getGUIObjectByName("mapSelection").list.length - 1)) + 1]); 824 916 825 917 g_GameAttributes.settings.mapType = g_GameAttributes.mapType; 826 918 var numPlayers = g_GameAttributes.settings.PlayerData.length; 827 919 // Assign random civilizations to players with that choice … … 894 986 } 895 987 // Remove extra player data 896 988 g_GameAttributes.settings.PlayerData = g_GameAttributes.settings.PlayerData.slice(0, numPlayers); 897 989 898 990 Engine.StartGame(g_GameAttributes, playerID); 899 991 Engine.SwitchGuiPage("page_loading.xml", { 900 992 "attribs": g_GameAttributes, … … 909 1001 function onGameAttributesChange() 910 1002 { 911 1003 g_IsInGuiUpdate = true; 912 1004 913 1005 // Don't set any attributes here, just show the changes in GUI 914 1006 915 1007 var mapName = g_GameAttributes.map || ""; 916 1008 var mapSettings = g_GameAttributes.settings; 917 1009 var numPlayers = (mapSettings.PlayerData ? mapSettings.PlayerData.length : MAX_PLAYERS); 918 1010 919 1011 // Update some controls for clients 920 1012 if (!g_IsController) 921 1013 { … … 932 1024 startingResourcesBox.selected = startingResourcesBox.list_data.indexOf(mapSettings.StartingResources); 933 1025 initMapNameList(); 934 1026 } 935 1027 936 1028 // Controls common to all map types 937 1029 var numPlayersSelection = getGUIObjectByName("numPlayersSelection"); 1030 var minNumPlayers = numPlayersSelection.list_data[0]; 938 1031 var revealMap = getGUIObjectByName("revealMap"); 939 1032 var victoryCondition = getGUIObjectByName("victoryCondition"); 940 1033 var lockTeams = getGUIObjectByName("lockTeams"); … … 966 1059 case "random": 967 1060 if (g_IsController) 968 1061 { //Host 969 numPlayersSelection.selected = numPlayers - 1;1062 numPlayersSelection.selected = numPlayers - minNumPlayers; 970 1063 numPlayersSelection.hidden = false; 971 1064 mapSize.hidden = false; 972 1065 revealMap.hidden = false; … … 1017 1110 victoryConditionText.caption = VICTORY_TEXT[victoryIdx]; 1018 1111 lockTeamsText.caption = (mapSettings.LockTeams ? "Yes" : "No"); 1019 1112 } 1020 1113 1021 1114 break; 1022 1115 1023 1116 case "scenario": 1024 1117 // For scenario just reflect settings for the current map 1025 1118 numPlayersSelection.hidden = true; … … 1045 1138 victoryConditionText.caption = VICTORY_TEXT[victoryIdx]; 1046 1139 lockTeamsText.caption = (mapSettings.LockTeams ? "Yes" : "No"); 1047 1140 getGUIObjectByName("populationCap").selected = POPULATION_CAP_DEFAULTIDX; 1048 1141 1049 1142 break; 1050 1143 1051 1144 default: 1052 1145 error("onGameAttributesChange: Unexpected map type '"+g_GameAttributes.mapType+"'"); 1053 1146 return; 1054 1147 } 1055 1148 1056 1149 // Display map name 1057 1150 getGUIObjectByName("mapInfoName").caption = getMapDisplayName(mapName); 1058 1151 1059 1152 // Load the description from the map file, if there is one 1060 1153 var description = mapSettings.Description || "Sorry, no description available."; 1061 1154 // Adding player caps to the map description 1155 if (g_GameAttributes.mapType == "random") 1156 { 1157 if (g_MapData[mapName] && g_MapData[mapName].settings && g_MapData[mapName].settings.MinimumPlayers) 1158 description += "\n\nMinimum number of players: " + g_MapData[mapName].settings.MinimumPlayers; 1159 else 1160 description += "\n"; 1161 description += "\nMaximum numbers of players (by map size):"; 1162 if (g_MapData[mapName] && g_MapData[mapName].settings && g_MapData[mapName].settings.MaximumPlayersByMapSize) 1163 description += "\nTiny: " + g_MapData[mapName].settings.MaximumPlayersByMapSize.toString().replace(/,/g, "-").replace("-", ", Small: ").replace("-", ", Medium: ").replace("-", ", Normal: ").replace("-", ", Large: ").replace("-", ", Very Large: ").replace("-", ", Giant: "); 1164 else 1165 description += "\nTiny: " + MAX_PLAYERS_BY_MAP_SIZE_RMS.toString().replace(/,/g, "-").replace("-", ", Small: ").replace("-", ", Medium: ").replace("-", ", Normal: ").replace("-", ", Large: ").replace("-", ", Very Large: ").replace("-", ", Giant: "); 1166 } 1167 // Add naval warning to the map description 1062 1168 if (g_GameAttributes.mapFilter == "Naval Maps") 1063 1169 description += g_NavalWarning; 1064 1170 1065 1171 // Describe the number of players 1066 1172 var playerString = numPlayers + " " + (numPlayers == 1 ? "player" : "players") + ". "; 1067 1173 1068 1174 for (var i = 0; i < MAX_PLAYERS; ++i) 1069 1175 { 1070 1176 // Show only needed player slots 1071 1177 getGUIObjectByName("playerBox["+i+"]").hidden = (i >= numPlayers); 1072 1178 1073 1179 // Show player data or defaults as necessary 1074 1180 if (i < numPlayers) 1075 1181 { … … 1083 1189 // Player data / defaults 1084 1190 var pData = mapSettings.PlayerData ? mapSettings.PlayerData[i] : {}; 1085 1191 var pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[i] : {}; 1086 1192 1087 1193 // Common to all game types 1088 1194 var color = iColorToString(getSetting(pData, pDefs, "Colour")); 1089 1195 pColor.sprite = "colour:"+color+" 100"; 1090 1196 pName.caption = getSetting(pData, pDefs, "Name"); 1091 1197 1092 1198 var team = getSetting(pData, pDefs, "Team"); 1093 1199 var civ = getSetting(pData, pDefs, "Civ"); 1094 1200 … … 1124 1230 } 1125 1231 1126 1232 getGUIObjectByName("mapInfoDescription").caption = playerString + description; 1127 1233 1128 1234 g_IsInGuiUpdate = false; 1129 1235 1130 1236 // Game attributes include AI settings, so update the player list 1131 1237 updatePlayerList(); 1132 1238 } … … 1146 1252 function updatePlayerList() 1147 1253 { 1148 1254 g_IsInGuiUpdate = true; 1149 1255 1150 1256 var hostNameList = []; 1151 1257 var hostGuidList = []; 1152 1258 var assignments = []; 1153 1259 var aiAssignments = {}; 1154 1260 var noAssignment; 1155 1261 var assignedCount = 0; 1156 1262 1157 1263 for (var guid in g_PlayerAssignments) 1158 1264 { 1159 1265 var name = g_PlayerAssignments[guid].name; 1160 1266 var hostID = hostNameList.length; 1161 1267 var player = g_PlayerAssignments[guid].player; 1162 1268 1163 1269 hostNameList.push(name); 1164 1270 hostGuidList.push(guid); 1165 1271 assignments[player] = hostID; 1166 1272 1167 1273 if (player != 255) 1168 1274 assignedCount++; 1169 1275 } 1170 1276 1171 1277 // Only enable start button if we have enough assigned players 1172 1278 if (g_IsController) 1173 1279 getGUIObjectByName("startGame").enabled = (assignedCount > 0); 1174 1280 1175 1281 for each (var ai in g_AIs) 1176 1282 { 1177 1283 if (ai.data.hidden) … … 1195 1301 hostNameList.push("[color=\"70 150 70 255\"]AI: " + ai.data.name); 1196 1302 hostGuidList.push("ai:" + ai.id); 1197 1303 } 1198 1304 1199 1305 noAssignment = hostNameList.length; 1200 1306 hostNameList.push("[color=\"140 140 140 255\"]Unassigned"); 1201 1307 hostGuidList.push(""); 1202 1308 1203 1309 for (var i = 0; i < MAX_PLAYERS; ++i) 1204 1310 { 1205 1311 let playerSlot = i; 1206 1312 let playerID = i+1; // we don't show Gaia, so first slot is ID 1 1207 1313 1208 1314 var selection = assignments[playerID]; 1209 1315 1210 1316 var configButton = getGUIObjectByName("playerConfig["+i+"]"); 1211 1317 configButton.hidden = true; 1212 1318 1213 1319 // Look for valid player slots 1214 1320 if (playerSlot < g_GameAttributes.settings.PlayerData.length) 1215 1321 { … … 1225 1331 else 1226 1332 warn("AI \""+aiId+"\" not present. Defaulting to unassigned."); 1227 1333 } 1228 1334 1229 1335 if (!selection) 1230 1336 selection = noAssignment; 1231 1337 1232 1338 // Since no human is assigned, show the AI config button 1233 1339 if (g_IsController) 1234 1340 { … … 1240 1346 id: g_GameAttributes.settings.PlayerData[playerSlot].AI, 1241 1347 callback: function(ai) { 1242 1348 g_GameAttributes.settings.PlayerData[playerSlot].AI = ai.id; 1243 1349 1244 1350 if (g_IsNetworked) 1245 1351 { 1246 1352 Engine.SetNetworkGameAttributes(g_GameAttributes); … … 1267 1373 } 1268 1374 } 1269 1375 } 1270 1376 1271 1377 var assignBox = getGUIObjectByName("playerAssignment["+i+"]"); 1272 1378 assignBox.list = hostNameList; 1273 1379 assignBox.list_data = hostGuidList; … … 1275 1381 { 1276 1382 assignBox.selected = selection; 1277 1383 } 1278 1384 1279 1385 if (g_IsNetworked && g_IsController) 1280 1386 { 1281 1387 assignBox.onselectionchange = function () … … 1299 1405 } 1300 1406 else 1301 1407 swapPlayers(guid, playerSlot); 1302 1408 1303 1409 Engine.SetNetworkGameAttributes(g_GameAttributes); 1304 1410 } 1305 1411 }; … … 1323 1429 } 1324 1430 else 1325 1431 swapPlayers(guid, playerSlot); 1326 1432 1327 1433 updatePlayerList(); 1328 1434 } 1329 1435 }; 1330 1436 } 1331 1437 } 1332 1438 } 1333 1439 1334 1440 g_IsInGuiUpdate = false; 1335 1441 } 1336 1442 … … 1339 1445 // Player slots are indexed from 0 as Gaia is omitted. 1340 1446 var newPlayerID = newSlot + 1; 1341 1447 var playerID = g_PlayerAssignments[guid].player; 1342 1448 1343 1449 // Attempt to swap the player or AI occupying the target slot, 1344 1450 // if any, into the slot this player is currently in. 1345 1451 if (playerID != 255) … … 1356 1462 break; 1357 1463 } 1358 1464 } 1359 1465 1360 1466 // Transfer the AI from the target slot to the current slot. 1361 1467 g_GameAttributes.settings.PlayerData[playerID - 1].AI = g_GameAttributes.settings.PlayerData[newSlot].AI; 1362 1468 } 1363 1469 1364 1470 if (g_IsNetworked) 1365 1471 Engine.AssignNetworkPlayer(newPlayerID, guid); 1366 1472 else 1367 1473 g_PlayerAssignments[guid].player = newPlayerID; 1368 1474 1369 1475 // Remove AI from this player slot 1370 1476 g_GameAttributes.settings.PlayerData[newSlot].AI = ""; 1371 1477 } … … 1385 1491 { 1386 1492 var username = escapeText(msg.username || g_PlayerAssignments[msg.guid].name); 1387 1493 var message = escapeText(msg.text); 1388 1494 1389 1495 // TODO: Maybe host should have distinct font/color? 1390 1496 var color = "white"; 1391 1497 1392 1498 if (g_PlayerAssignments[msg.guid] && g_PlayerAssignments[msg.guid].player != 255) 1393 1499 { // Valid player who has been assigned - get player colour 1394 1500 var player = g_PlayerAssignments[msg.guid].player - 1; … … 1397 1503 var mapSettings = (mapData && mapData.settings ? mapData.settings : {}); 1398 1504 var pData = mapSettings.PlayerData ? mapSettings.PlayerData[player] : {}; 1399 1505 var pDefs = g_DefaultPlayerData ? g_DefaultPlayerData[player] : {}; 1400 1506 1401 1507 color = iColorToString(getSetting(pData, pDefs, "Colour")); 1402 1508 } 1403 1509 1404 1510 var formatted; 1405 1511 switch (msg.type) 1406 1512 { 1407 1513 case "connect": 1408 1514 formatted = '[font="serif-bold-13"][color="'+ color +'"]' + username + '[/color][/font] [color="gold"]has joined[/color]'; 1409 1515 break; 1410 1516 1411 1517 case "disconnect": 1412 1518 formatted = '[font="serif-bold-13"][color="'+ color +'"]' + username + '[/color][/font] [color="gold"]has left[/color]'; 1413 1519 break; 1414 1520 1415 1521 case "message": 1416 1522 formatted = '[font="serif-bold-13"]<[color="'+ color +'"]' + username + '[/color]>[/font] ' + message; 1417 1523 break; 1418 1524 1419 1525 default: 1420 1526 error("Invalid chat message '" + uneval(msg) + "'"); 1421 1527 return; 1422 1528 } 1423 1529 1424 1530 g_ChatMessages.push(formatted); 1425 1531 1426 1532 getGUIObjectByName("chatText").caption = g_ChatMessages.join("\n"); 1427 1533 } 1428 1534 … … 1442 1548 var newFilter = {}; 1443 1549 newFilter.name = name; 1444 1550 newFilter.filter = filterFunc; 1445 1551 1446 1552 g_MapFilters.push(newFilter); 1447 1553 } 1448 1554 else … … 1459 1565 { 1460 1566 filters.push(g_MapFilters[i].name); 1461 1567 } 1462 1568 1463 1569 return filters; 1464 1570 } 1465 1571 … … 1473 1579 return g_MapFilters[i].filter(mapSettings); 1474 1580 } 1475 1581 } 1476 1582 1477 1583 error("Invalid map filter: "+name); 1478 1584 return false; 1479 1585 } … … 1485 1591 { 1486 1592 return false; 1487 1593 } 1488 1594 1489 1595 for (var m = 0; m < matches.length; ++m) 1490 1596 { // Fail on not match 1491 1597 if (keywords.indexOf(matches[m]) == -1) … … 1503 1609 { 1504 1610 return false; 1505 1611 } 1506 1612 1507 1613 for (var m = 0; m < matches.length; ++m) 1508 1614 { // Success on match 1509 1615 if (keywords.indexOf(matches[m]) != -1) -
binaries/data/mods/public/maps/random/archipelago.json
8 8 "Keywords": ["naval"], 9 9 "Preview" : "archipelago.png", 10 10 "CircularMap" : true, 11 "MaximumPlayersByMapSize" : [3, 6, 8, 8, 8, 8, 8], 11 12 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 12 13 } 13 14 } -
binaries/data/mods/public/maps/random/belgian_uplands.json
2 2 "settings" : { 3 3 "Name" : "Belgian Uplands", 4 4 "Script" : "belgian_uplands.js", 5 "Preview" : "belgian_uplands.png", 5 6 "Description" : "An experimental map with its hightmap generated by erosion to look more natural. Not all seeds will be fair though! Tiny maps with 8 players may take a while to generate.", 6 7 "CircularMap" : false, 8 "MaximumPlayersByMapSize" : [2, 4, 6, 8, 8, 8, 8], 7 9 "BaseTerrain" : ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_d", "temp_grass_long_b", "temp_grass_clovers_2", "temp_grass_mossy", "temp_grass_plants"], 8 10 "BaseHeight" : 0, 9 "Preview" : "belgian_uplands.png",10 11 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 11 12 } 12 13 } -
binaries/data/mods/public/maps/random/canyon.json
7 7 "BaseHeight" : 30, 8 8 "Preview" : "canyon.png", 9 9 "CircularMap" : true, 10 "MinimumPlayers" : 2, 11 "MaximumPlayersByMapSize" : [3, 6, 8, 8, 8, 8, 8], 10 12 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 11 13 } 12 14 } 15 No newline at end of file -
binaries/data/mods/public/maps/random/corsica.json
8 8 "Keywords": ["naval"], 9 9 "Preview" : "corsica.png", 10 10 "CircularMap" : false, 11 "MaximumPlayersByMapSize" : [2, 4, 6, 8, 8, 8, 8], 11 12 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 12 13 } 13 14 } 15 No newline at end of file -
binaries/data/mods/public/maps/random/deep_forest.json
7 7 "BaseHeight" : 0, 8 8 "Preview" : "deep_forest.png", 9 9 "CircularMap" : true, 10 "MaximumPlayersByMapSize" : [3, 6, 8, 8, 8, 8, 8], 10 11 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 11 12 } 12 13 } -
binaries/data/mods/public/maps/random/guadalquivir_river.js
142 142 createArea(placer, painter, null); 143 143 144 144 // create starting units 145 placeCivDefaultEntities(fx, fz, id, BUILDING_ANGlE );145 placeCivDefaultEntities(fx, fz, id, BUILDING_ANGlE, (mapSize/64 - 3 < 1) ? {"iberWall" : false} : undefined); 146 146 147 147 // create animals 148 148 for (var j = 0; j < 2; ++j) -
binaries/data/mods/public/maps/random/guadalquivir_river.json
7 7 "BaseHeight" : -5, 8 8 "Preview" : "guadalquivir_river.png", 9 9 "CircularMap" : true, 10 "MaximumPlayersByMapSize" : [2, 4, 6, 6, 8, 8, 8], 10 11 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 11 12 } 12 13 } -
binaries/data/mods/public/maps/random/gulf_of_bothnia.json
7 7 "BaseHeight" : 3, 8 8 "Preview" : "gulf_of_bothnia.png", 9 9 "CircularMap" : true, 10 "MinimumPlayers" : 2, 10 11 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 11 12 } 12 13 } 14 No newline at end of file -
binaries/data/mods/public/maps/random/islands.json
8 8 "Keywords": ["naval"], 9 9 "Preview" : "islands.png", 10 10 "CircularMap" : true, 11 "MaximumPlayersByMapSize" : [2, 4, 6, 8, 8, 8, 8], 11 12 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 12 13 } 13 14 } -
binaries/data/mods/public/maps/random/migration.json
8 8 "Keywords": ["naval"], 9 9 "Preview" : "migration.png", 10 10 "CircularMap" : true, 11 "MaximumPlayersByMapSize" : [2, 3, 5, 5, 6, 7, 8], 11 12 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 12 13 } 13 14 } -
binaries/data/mods/public/maps/random/pheonician_levant.json
7 7 "BaseHeight" : 1, 8 8 "Preview" : "phoenician_levant.png", 9 9 "CircularMap" : false, 10 "MaximumPlayersByMapSize" : [4, 4, 8, 8, 8, 8, 8], 10 11 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 11 12 } 12 13 } 14 No newline at end of file -
binaries/data/mods/public/maps/random/pyrenean_sierra.js
351 351 createArea(placer, painter, null); 352 352 353 353 // create starting units 354 placeCivDefaultEntities(fx, fz, id, BUILDING_ANGlE );354 placeCivDefaultEntities(fx, fz, id, BUILDING_ANGlE, (round(mapSize/64) - 2 == 1) ? {"iberWall" : "towers"} : undefined); 355 355 356 356 // create animals 357 357 for (var j = 0; j < 2; ++j) -
binaries/data/mods/public/maps/random/pyrenean_sierra.json
7 7 "BaseHeight" : -100, 8 8 "Preview" : "pyrenean_sierra.png", 9 9 "CircularMap" : true, 10 "MinimumPlayers" : 2, 10 11 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 11 12 } 12 13 } 14 No newline at end of file -
binaries/data/mods/public/maps/random/snowflake_searocks.json
7 7 "BaseHeight" : -5, 8 8 "Preview" : "snowflake_searocks.png", 9 9 "CircularMap" : true, 10 "MinimumPlayers" : 2, 11 "MaximumPlayersByMapSize" : [3, 4, 8, 8, 8, 8, 8], 10 12 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 11 13 } 12 14 } -
binaries/data/mods/public/maps/random/unknown.json
7 7 "BaseHeight" : -5, 8 8 "Preview" : "unknown.png", 9 9 "CircularMap" : true, 10 "MinimumPlayers" : 2, 11 "MaximumPlayersByMapSize" : [2, 4, 6, 8, 8, 8, 8], 10 12 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 11 13 } 12 14 } -
binaries/data/mods/public/maps/random/unknown_land.json
7 7 "BaseHeight" : -5, 8 8 "Preview" : "unknown.png", 9 9 "CircularMap" : true, 10 "MinimumPlayers" : 2, 11 "MaximumPlayersByMapSize" : [2, 4, 6, 8, 8, 8, 8], 10 12 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 11 13 } 12 14 } -
binaries/data/mods/public/maps/random/unknown_nomad.json
8 8 "Preview" : "unknown.png", 9 9 "Keywords": ["demo"], 10 10 "CircularMap" : true, 11 "MinimumPlayers" : 2, 12 "MaximumPlayersByMapSize" : [2, 4, 6, 8, 8, 8, 8], 11 13 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 12 14 } 13 15 }