Ticket #3702: lockedTeams3.patch
File lockedTeams3.patch, 15.1 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/gui/session/menu.js
const g_IdleTraderTextColor = "orange"; 34 34 var g_IsMenuOpen = false; 35 35 36 36 var g_IsDiplomacyOpen = false; 37 37 var g_IsTradeOpen = false; 38 38 39 // Redefined every time someone makes a tribute (so we can save some data in a closure). Called in input.js handleInputBeforeGui. 39 /** 40 * Redefined every time someone makes a tribute (so we can save some data in a closure). 41 * Called in input.js handleInputBeforeGui. 42 */ 40 43 var g_FlushTributing = function() {}; 41 44 42 45 // Ignore size defined in XML and set the actual menu size here 43 46 function initMenuPosition() 44 47 { … … function toggleChatWindow(teamChat) 252 255 253 256 updateTeamCheckbox(teamChat); 254 257 chatWindow.hidden = !hidden; 255 258 } 256 259 257 function setDiplomacy(data)258 {259 Engine.PostNetworkCommand({ "type": "diplomacy", "to": data.to, "player": data.player });260 }261 262 function tributeResource(data)263 {264 Engine.PostNetworkCommand({ "type": "tribute", "player": data.player, "amounts": data.amounts });265 }266 267 260 function openDiplomacy() 268 261 { 269 262 closeOpenDialogs(); 270 263 271 264 if (g_ViewedPlayer < 1) 272 265 return; 273 266 274 267 g_IsDiplomacyOpen = true; 275 268 276 269 let isCeasefireActive = GetSimState().ceasefireActive; 270 for (let i = 1; i < g_Players.length; ++i) 271 { 272 diplomacySetupTexts(i); 273 274 let playerInactive = i == g_ViewedPlayer || isPlayerObserver(g_ViewedPlayer) || isPlayerObserver(i); 275 let hasAllies = g_Players.filter(player => player.isMutualAlly[g_ViewedPlayer]).length > 1; 276 277 diplomacyFormatTributeButtons(i, playerInactive); 278 diplomacyFormatStanceButtons(i, playerInactive || isCeasefireActive || g_Players[g_ViewedPlayer].teamsLocked); 279 diplomacyFormatAttackRequestButton(i, playerInactive || isCeasefireActive || !hasAllies || !g_Players[i].isEnemy[g_ViewedPlayer]); 280 } 281 282 Engine.GetGUIObjectByName("diplomacyDialogPanel").hidden = false; 283 } 277 284 285 function diplomacySetupTexts(i) 286 { 278 287 // Get offset for one line 279 288 let onesize = Engine.GetGUIObjectByName("diplomacyPlayer[0]").size; 280 289 let rowsize = onesize.bottom - onesize.top; 281 290 282 // We don't include gaia 283 for (let i = 1; i < g_Players.length; ++i) 284 { 285 // Apply offset 286 let row = Engine.GetGUIObjectByName("diplomacyPlayer["+(i-1)+"]"); 287 let size = row.size; 288 size.top = rowsize*(i-1); 289 size.bottom = rowsize*i; 290 row.size = size; 291 292 // Set background color 293 let playerColor = rgbToGuiColor(g_Players[i].color); 294 row.sprite = "color: "+playerColor + " 32"; 295 296 Engine.GetGUIObjectByName("diplomacyPlayerName["+(i-1)+"]").caption = "[color=\"" + playerColor + "\"]" + g_Players[i].name + "[/color]"; 297 Engine.GetGUIObjectByName("diplomacyPlayerCiv["+(i-1)+"]").caption = g_CivData[g_Players[i].civ].Name; 298 Engine.GetGUIObjectByName("diplomacyPlayerTeam["+(i-1)+"]").caption = (g_Players[i].team < 0) ? translateWithContext("team", "None") : g_Players[i].team+1; 299 Engine.GetGUIObjectByName("diplomacyPlayerTheirs["+(i-1)+"]").caption = (i == g_ViewedPlayer) ? "" : (g_Players[i].isAlly[g_ViewedPlayer] ? translate("Ally") : (g_Players[i].isNeutral[g_ViewedPlayer] ? translate("Neutral") : translate("Enemy"))); 291 let row = Engine.GetGUIObjectByName("diplomacyPlayer["+(i-1)+"]"); 292 let size = row.size; 293 size.top = rowsize*(i-1); 294 size.bottom = rowsize*i; 295 row.size = size; 296 row.sprite = "color: " + rgbToGuiColor(g_Players[i].color) + " 32"; 300 297 301 // Don't display the options for ourself, or if we or the other player aren't active anymore 302 if (i == g_ViewedPlayer || g_Players[i].state != "active") 303 { 304 // Hide the unused/unselectable options 305 for (let a of ["TributeFood", "TributeWood", "TributeStone", "TributeMetal", "Ally", "Neutral", "Enemy"]) 306 Engine.GetGUIObjectByName("diplomacyPlayer"+a+"["+(i-1)+"]").hidden = true; 307 Engine.GetGUIObjectByName("diplomacyAttackRequest["+(i-1)+"]").hidden = true; 308 continue; 309 } 298 Engine.GetGUIObjectByName("diplomacyPlayerName["+(i-1)+"]").caption = colorizePlayernameByID(i); 299 Engine.GetGUIObjectByName("diplomacyPlayerCiv["+(i-1)+"]").caption = g_CivData[g_Players[i].civ].Name; 310 300 311 // Tribute 312 for (let resource of RESOURCES) 313 { 314 let button = Engine.GetGUIObjectByName("diplomacyPlayerTribute"+resource[0].toUpperCase()+resource.substring(1)+"["+(i-1)+"]"); 315 button.onpress = (function(player, resource, button){ 316 // Implement something like how unit batch training works. Shift+click to send 500, shift+click+click to send 1000, etc. 317 // Also see input.js (searching for "INPUT_MASSTRIBUTING" should get all the relevant parts). 318 let multiplier = 1; 319 return function() { 320 let isBatchTrainPressed = Engine.HotkeyIsPressed("session.masstribute"); 321 if (isBatchTrainPressed) 322 { 323 inputState = INPUT_MASSTRIBUTING; 324 multiplier += multiplier == 1 ? 4 : 5; 325 } 326 let amounts = { 327 "food": (resource == "food" ? 100 : 0) * multiplier, 328 "wood": (resource == "wood" ? 100 : 0) * multiplier, 329 "stone": (resource == "stone" ? 100 : 0) * multiplier, 330 "metal": (resource == "metal" ? 100 : 0) * multiplier 331 }; 332 button.tooltip = formatTributeTooltip(g_Players[player], resource, amounts[resource]); 333 // This is in a closure so that we have access to `player`, `amounts`, and `multiplier` without some 334 // evil global variable hackery. 335 g_FlushTributing = function() { 336 tributeResource({ "player": player, "amounts": amounts }); 337 multiplier = 1; 338 button.tooltip = formatTributeTooltip(g_Players[player], resource, 100); 339 }; 340 if (!isBatchTrainPressed) 341 g_FlushTributing(); 342 }; 343 })(i, resource, button); 344 button.enabled = controlsPlayer(g_ViewedPlayer); 345 button.hidden = false; 346 button.tooltip = formatTributeTooltip(g_Players[i], resource, 100); 347 } 301 Engine.GetGUIObjectByName("diplomacyPlayerTeam["+(i-1)+"]").caption = 302 g_Players[i].team < 0 ? translateWithContext("team", "None") : g_Players[i].team+1; 348 303 349 // Attack Request 350 let button = Engine.GetGUIObjectByName("diplomacyAttackRequest["+(i-1)+"]"); 351 button.hidden = isCeasefireActive || !g_Players[i].isEnemy[g_ViewedPlayer]; 352 button.enabled = controlsPlayer(g_ViewedPlayer); 353 button.tooltip = translate("Request your allies to attack this enemy"); 354 button.onpress = (function(i) { return function() { 355 Engine.PostNetworkCommand({ "type": "attack-request", "source": g_ViewedPlayer, "target": i }); 356 }; })(i); 304 Engine.GetGUIObjectByName("diplomacyPlayerTheirs["+(i-1)+"]").caption = 305 i == g_ViewedPlayer ? "" : 306 g_Players[i].isAlly[g_ViewedPlayer] ? translate("Ally") : 307 g_Players[i].isNeutral[g_ViewedPlayer] ? translate("Neutral") : translate("Enemy"); 308 } 357 309 358 // Skip our own teams on teams locked 359 if (g_Players[g_ViewedPlayer].teamsLocked && g_Players[g_ViewedPlayer].team != -1 && g_Players[g_ViewedPlayer].team == g_Players[i].team) 310 function diplomacyFormatTributeButtons(i, hidden) 311 { 312 for (let resource of RESOURCES) 313 { 314 let button = Engine.GetGUIObjectByName("diplomacyPlayerTribute"+resource[0].toUpperCase()+resource.substring(1)+"["+(i-1)+"]"); 315 button.hidden = hidden; 316 if (hidden) 360 317 continue; 318 button.enabled = controlsPlayer(g_ViewedPlayer); 319 button.tooltip = formatTributeTooltip(g_Players[i], resource, 100); 320 button.onpress = (function(i, resource, button) { 321 // Shift+click to send 500, shift+click+click to send 1000, etc. 322 // Also see INPUT_MASSTRIBUTING in input.js 323 let multiplier = 1; 324 return function() { 325 let isBatchTrainPressed = Engine.HotkeyIsPressed("session.masstribute"); 326 if (isBatchTrainPressed) 327 { 328 inputState = INPUT_MASSTRIBUTING; 329 multiplier += multiplier == 1 ? 4 : 5; 330 } 331 let amounts = { 332 "food": (resource == "food" ? 100 : 0) * multiplier, 333 "wood": (resource == "wood" ? 100 : 0) * multiplier, 334 "stone": (resource == "stone" ? 100 : 0) * multiplier, 335 "metal": (resource == "metal" ? 100 : 0) * multiplier 336 }; 337 button.tooltip = formatTributeTooltip(g_Players[i], resource, amounts[resource]); 338 // This is in a closure so that we have access to `player`, `amounts`, and `multiplier` without some 339 // evil global variable hackery. 340 g_FlushTributing = function() { 341 Engine.PostNetworkCommand({ "type": "tribute", "player": i, "amounts": amounts }); 342 multiplier = 1; 343 button.tooltip = formatTributeTooltip(g_Players[i], resource, 100); 344 }; 345 if (!isBatchTrainPressed) 346 g_FlushTributing(); 347 }; 348 })(i, resource, button); 349 } 350 } 361 351 362 // Diplomacy settings 363 // Set up the buttons 364 for (let setting of ["Ally", "Neutral", "Enemy"]) 365 { 366 let button = Engine.GetGUIObjectByName("diplomacyPlayer"+setting+"["+(i-1)+"]"); 352 function diplomacyFormatAttackRequestButton(i, hidden) 353 { 354 let button = Engine.GetGUIObjectByName("diplomacyAttackRequest["+(i-1)+"]"); 355 button.hidden = hidden; 356 if (hidden) 357 return; 367 358 368 button.caption = g_Players[g_ViewedPlayer]["is" + setting][i] ? translate("x") : "";369 button.onpress = (function(e){ return function() { setDiplomacy(e); }; })({ "player": i, "to": setting.toLowerCase() });370 button.enabled = controlsPlayer(g_ViewedPlayer);371 button.hidden = isCeasefireActive;372 }373 359 button.enabled = controlsPlayer(g_ViewedPlayer); 360 button.tooltip = translate("Request your allies to attack this enemy"); 361 button.onpress = (function(i) { return function() { 362 Engine.PostNetworkCommand({ "type": "attack-request", "source": g_ViewedPlayer, "target": i }); 363 }; })(i); 364 } 374 365 375 Engine.GetGUIObjectByName("diplomacyDialogPanel").hidden = false; 366 function diplomacyFormatStanceButtons(i, hidden) 367 { 368 for (let stance of ["Ally", "Neutral", "Enemy"]) 369 { 370 let button = Engine.GetGUIObjectByName("diplomacyPlayer"+stance+"["+(i-1)+"]"); 371 button.hidden = hidden; 372 if (hidden) 373 continue; 374 375 button.caption = g_Players[g_ViewedPlayer]["is" + stance][i] ? translate("x") : ""; 376 button.enabled = controlsPlayer(g_ViewedPlayer); 377 button.onpress = (function(player, stance) { return function() { 378 Engine.PostNetworkCommand({ "type": "diplomacy", "player": i, "to": stance.toLowerCase() }); 379 }; })(i, stance); 380 } 376 381 } 377 382 378 383 function closeDiplomacy() 379 384 { 380 385 g_IsDiplomacyOpen = false; -
binaries/data/mods/public/simulation/components/Player.js
Player.prototype.GetTeam = function() 361 361 return this.team; 362 362 }; 363 363 364 364 Player.prototype.SetTeam = function(team) 365 365 { 366 if (!this.teamsLocked) 367 { 368 this.team = team; 366 this.team = team; 369 367 370 var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 371 if (cmpPlayerManager && this.team != -1) 368 let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 369 if (cmpPlayerManager && this.team != -1) 370 { 371 // Set all team members as allies 372 for (let i = 0; i < cmpPlayerManager.GetNumPlayers(); ++i) 372 373 { 373 // Set all team members as allies 374 for (var i = 0; i < cmpPlayerManager.GetNumPlayers(); ++i) 375 { 376 var cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(i), IID_Player); 377 if (this.team == cmpPlayer.GetTeam()) 378 { 379 this.SetAlly(i); 380 cmpPlayer.SetAlly(this.playerID); 381 } 382 } 383 } 374 let cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(i), IID_Player); 375 if (this.team != cmpPlayer.GetTeam()) 376 continue; 384 377 385 Engine.BroadcastMessage(MT_DiplomacyChanged, {"player": this.playerID}); 378 this.SetAlly(i); 379 cmpPlayer.SetAlly(this.playerID); 380 } 386 381 } 382 383 Engine.BroadcastMessage(MT_DiplomacyChanged, { "player": this.playerID }); 387 384 }; 388 385 389 386 Player.prototype.SetLockTeams = function(value) 390 387 { 391 388 this.teamsLocked = value; … … Player.prototype.GetDiplomacy = function 401 398 return this.diplomacy; 402 399 }; 403 400 404 401 Player.prototype.SetDiplomacy = function(dipl) 405 402 { 406 // Should we check for teamsLocked here?407 403 this.diplomacy = dipl; 408 Engine.BroadcastMessage(MT_DiplomacyChanged, { "player": this.playerID});404 Engine.BroadcastMessage(MT_DiplomacyChanged, { "player": this.playerID }); 409 405 }; 410 406 411 407 Player.prototype.SetDiplomacyIndex = function(idx, value) 412 408 { 413 409 var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); … … Player.prototype.SetDiplomacyIndex = fun 419 415 return; 420 416 421 417 if (this.state != "active" || cmpPlayer.state != "active") 422 418 return; 423 419 424 // You can have alliances with other players, 425 if (this.teamsLocked) 426 { 427 // but can't stab your team members in the back 428 if (this.team == -1 || this.team != cmpPlayer.GetTeam()) 429 { 430 // Break alliance or declare war 431 if (Math.min(this.diplomacy[idx],cmpPlayer.diplomacy[this.playerID]) > value) 432 { 433 this.diplomacy[idx] = value; 434 cmpPlayer.SetDiplomacyIndex(this.playerID, value); 435 } 436 else 437 { 438 this.diplomacy[idx] = value; 439 } 440 Engine.BroadcastMessage(MT_DiplomacyChanged, {"player": this.playerID}); 441 } 442 } 443 else 444 { 445 // Break alliance or declare war (worsening of relations is mutual) 446 if (Math.min(this.diplomacy[idx],cmpPlayer.diplomacy[this.playerID]) > value) 447 { 448 // This is duplicated because otherwise we get too much recursion 449 this.diplomacy[idx] = value; 450 cmpPlayer.SetDiplomacyIndex(this.playerID, value); 451 } 452 else 453 { 454 this.diplomacy[idx] = value; 455 } 420 this.diplomacy[idx] = value; 421 Engine.BroadcastMessage(MT_DiplomacyChanged, { "player": this.playerID }); 456 422 457 Engine.BroadcastMessage(MT_DiplomacyChanged, {"player": this.playerID}); 458 } 423 // Mutual worsening of relations 424 if (cmpPlayer.diplomacy[this.playerID] > value) 425 cmpPlayer.SetDiplomacyIndex(this.playerID, value); 459 426 }; 460 427 461 428 Player.prototype.UpdateSharedLos = function() 462 429 { 463 430 let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); -
binaries/data/mods/public/simulation/helpers/Commands.js
var g_Commands = { 73 73 cmpGuiInterface.PushNotification({"type": "quit", "players": [player]}); 74 74 }, 75 75 76 76 "diplomacy": function(player, cmd, data) 77 77 { 78 if (data.cmpPlayer.GetLockTeams()) 79 { 80 warn("Can't change diplomacy of player " + player + " since teams are locked."); 81 return; 82 } 83 84 let cmpCeasefireManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager); 85 if (cmpCeasefireManager && cmpCeasefireManager.IsCeasefireActive()) 86 { 87 warn("Can't change diplomacy of player " + player + " while ceasefire is active."); 88 return; 89 } 90 78 91 switch(cmd.to) 79 92 { 80 93 case "ally": 81 94 data.cmpPlayer.SetAlly(cmd.player); 82 95 break; … … var g_Commands = { 87 100 data.cmpPlayer.SetEnemy(cmd.player); 88 101 break; 89 102 default: 90 103 warn("Invalid command: Could not set "+player+" diplomacy status of player "+cmd.player+" to "+cmd.to); 91 104 } 105 92 106 var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 93 107 cmpGuiInterface.PushNotification({ 94 108 "type": "diplomacy", 95 109 "players": [player], 96 110 "targetPlayer": cmd.player,