1
0
forked from mirrors/0ad

Hint the location for "You have been attacked" notifications

Icon edited by Stan.
Fixes: #5132
Differential Revision: https://code.wildfiregames.com/D1461
This was SVN commit r24565.
This commit is contained in:
Imarok
2021-01-12 19:13:16 +00:00
parent 1449ddf439
commit a3eccc043d
12 changed files with 162 additions and 77 deletions
@@ -10,6 +10,7 @@
<include>common/sprites.xml</include>
<include>common/styles.xml</include>
<include>session/setup.xml</include>
<include>session/sprites.xml</include>
<include>session/styles.xml</include>
<include>session/session.xml</include>
@@ -57,7 +57,7 @@ class ChatHistory
{
// Save to chat history
let historical = {
"txt": formatted,
"txt": formatted.text,
"timePrefix": sprintf(translate("\\[%(time)s]"), {
"time": Engine.FormatMillisecondsIntoDateStringLocal(Date.now(), translate("HH:mm"))
}),
@@ -9,7 +9,7 @@ ChatMessageFormatNetwork.clientlist = class
{
parse()
{
return getUsernameList();
return { "text": getUsernameList() };
}
};
@@ -17,13 +17,15 @@ ChatMessageFormatNetwork.connect = class
{
parse(msg)
{
return sprintf(
g_PlayerAssignments[msg.guid].player != -1 ?
// Translation: A player that left the game joins again
translate("%(player)s is starting to rejoin the game.") :
// Translation: A player joins the game for the first time
translate("%(player)s is starting to join the game."),
{ "player": colorizePlayernameByGUID(msg.guid) });
return {
"text": sprintf(
g_PlayerAssignments[msg.guid].player != -1 ?
// Translation: A player that left the game joins again
translate("%(player)s is starting to rejoin the game.") :
// Translation: A player joins the game for the first time
translate("%(player)s is starting to join the game."),
{ "player": colorizePlayernameByGUID(msg.guid) })
};
}
};
@@ -31,9 +33,11 @@ ChatMessageFormatNetwork.disconnect = class
{
parse(msg)
{
return sprintf(translate("%(player)s has left the game."), {
"player": colorizePlayernameByGUID(msg.guid)
});
return {
"text": sprintf(translate("%(player)s has left the game."), {
"player": colorizePlayernameByGUID(msg.guid)
})
};
}
};
@@ -41,16 +45,18 @@ ChatMessageFormatNetwork.kicked = class
{
parse(msg)
{
return sprintf(
msg.banned ?
translate("%(username)s has been banned") :
translate("%(username)s has been kicked"),
{
"username": colorizePlayernameHelper(
msg.username,
g_Players.findIndex(p => p.name == msg.username)
)
});
return {
"text": sprintf(
msg.banned ?
translate("%(username)s has been banned") :
translate("%(username)s has been kicked"),
{
"username": colorizePlayernameHelper(
msg.username,
g_Players.findIndex(p => p.name == msg.username)
)
})
};
}
};
@@ -58,12 +64,14 @@ ChatMessageFormatNetwork.rejoined = class
{
parse(msg)
{
return sprintf(
g_PlayerAssignments[msg.guid].player != -1 ?
// Translation: A player that left the game joins again
translate("%(player)s has rejoined the game.") :
// Translation: A player joins the game for the first time
translate("%(player)s has joined the game."),
{ "player": colorizePlayernameByGUID(msg.guid) });
return {
"text": sprintf(
g_PlayerAssignments[msg.guid].player != -1 ?
// Translation: A player that left the game joins again
translate("%(player)s has rejoined the game.") :
// Translation: A player joins the game for the first time
translate("%(player)s has joined the game."),
{ "player": colorizePlayernameByGUID(msg.guid) })
};
}
};
@@ -54,12 +54,14 @@ class ChatMessageFormatPlayer
// GUID for players, playerID for AIs
let coloredUsername = msg.guid != -1 ? colorizePlayernameByGUID(msg.guid) : colorizePlayernameByID(msg.player);
return sprintf(translate(this.strings[isMe ? "me" : "regular"][msg.context ? "context" : "no-context"]), {
"message": msg.text,
"context": msg.context ? translateWithContext("chat message context", msg.context) : "",
"user": coloredUsername,
"userTag": sprintf(translate("<%(user)s>"), { "user": coloredUsername })
});
return {
"text": sprintf(translate(this.strings[isMe ? "me" : "regular"][msg.context ? "context" : "no-context"]), {
"message": msg.text,
"context": msg.context ? translateWithContext("chat message context", msg.context) : "",
"user": coloredUsername,
"userTag": sprintf(translate("<%(user)s>"), { "user": coloredUsername })
})
};
}
/**
@@ -13,12 +13,22 @@ ChatMessageFormatSimulation.attack = class
return "";
let message = msg.targetIsDomesticAnimal ?
translate("Your livestock has been attacked by %(attacker)s!") :
translate("You have been attacked by %(attacker)s!");
translate("%(icon)sYour livestock has been attacked by %(attacker)s!") :
translate("%(icon)sYou have been attacked by %(attacker)s!");
return sprintf(message, {
"attacker": colorizePlayernameByID(msg.attacker)
});
return {
"text": sprintf(message, {
"icon": '[icon="icon_focusattacked"]',
"attacker": colorizePlayernameByID(msg.attacker)
}),
"callback": ((entityId, position) => function() {
if (GetEntityState(entityId))
setCameraFollow(entityId);
else
Engine.SetCameraTarget(position.x, position.y, position.z);
})(msg.target, msg.position),
"tooltip": translate("Click to focus on the attacked unit.")
};
}
};
@@ -35,11 +45,13 @@ ChatMessageFormatSimulation.barter = class
let amountGained = {};
amountGained[msg.resourceGained] = msg.amountGained;
return sprintf(translate("%(player)s bartered %(amountGiven)s for %(amountGained)s."), {
"player": colorizePlayernameByID(msg.player),
"amountGiven": getLocalizedResourceAmounts(amountGiven),
"amountGained": getLocalizedResourceAmounts(amountGained)
});
return {
"text": sprintf(translate("%(player)s bartered %(amountGiven)s for %(amountGained)s."), {
"player": colorizePlayernameByID(msg.player),
"amountGiven": getLocalizedResourceAmounts(amountGiven),
"amountGained": getLocalizedResourceAmounts(amountGained)
})
};
}
};
@@ -58,10 +70,12 @@ ChatMessageFormatSimulation.diplomacy = class
else
return "";
return sprintf(translate(this.strings[messageType][msg.status]), {
"player": colorizePlayernameByID(messageType == "active" ? msg.targetPlayer : msg.sourcePlayer),
"player2": colorizePlayernameByID(messageType == "active" ? msg.sourcePlayer : msg.targetPlayer)
});
return {
"text": sprintf(translate(this.strings[messageType][msg.status]), {
"player": colorizePlayernameByID(messageType == "active" ? msg.targetPlayer : msg.sourcePlayer),
"player2": colorizePlayernameByID(messageType == "active" ? msg.sourcePlayer : msg.targetPlayer)
})
};
}
};
@@ -102,10 +116,12 @@ ChatMessageFormatSimulation.phase = class
if (msg.phaseState == "completed")
message = translate("%(player)s has reached the %(phaseName)s.");
return sprintf(message, {
"player": colorizePlayernameByID(msg.player),
"phaseName": getEntityNames(GetTechnologyData(msg.phaseName, g_Players[msg.player].civ))
});
return {
"text": sprintf(message, {
"player": colorizePlayernameByID(msg.player),
"phaseName": getEntityNames(GetTechnologyData(msg.phaseName, g_Players[msg.player].civ))
})
};
}
};
@@ -114,18 +130,22 @@ ChatMessageFormatSimulation.playerstate = class
parse(msg)
{
if (!msg.message.pluralMessage)
return sprintf(translate(msg.message), {
"player": colorizePlayernameByID(msg.players[0])
});
return {
"text": sprintf(translate(msg.message), {
"player": colorizePlayernameByID(msg.players[0])
})
};
let mPlayers = msg.players.map(playerID => colorizePlayernameByID(playerID));
let lastPlayer = mPlayers.pop();
return sprintf(translatePlural(msg.message.message, msg.message.pluralMessage, msg.message.pluralCount), {
// Translation: This comma is used for separating first to penultimate elements in an enumeration.
"players": mPlayers.join(translate(", ")),
"lastPlayer": lastPlayer
});
return {
"text": sprintf(translatePlural(msg.message.message, msg.message.pluralMessage, msg.message.pluralCount), {
// Translation: This comma is used for separating first to penultimate elements in an enumeration.
"players": mPlayers.join(translate(", ")),
"lastPlayer": lastPlayer
})
};
}
};
@@ -148,10 +168,12 @@ ChatMessageFormatSimulation.tribute = class
g_Players[msg.targetPlayer].isMutualAlly[Engine.GetPlayerID()]))
message = translate("%(player)s has sent %(player2)s %(amounts)s.");
return sprintf(message, {
"player": colorizePlayernameByID(msg.sourcePlayer),
"player2": colorizePlayernameByID(msg.targetPlayer),
"amounts": getLocalizedResourceAmounts(msg.amounts)
});
return {
"text": sprintf(message, {
"player": colorizePlayernameByID(msg.sourcePlayer),
"player2": colorizePlayernameByID(msg.targetPlayer),
"amounts": getLocalizedResourceAmounts(msg.amounts)
})
};
}
};
@@ -68,9 +68,9 @@ class ChatMessageHandler
for (let messageFormat of this.messageFormats[msg.type])
{
let txt = messageFormat.parse(msg);
if (txt)
return txt;
let formatted = messageFormat.parse(msg);
if (formatted)
return formatted;
}
return undefined;
@@ -8,7 +8,7 @@ class ChatOverlay
/**
* Maximum number of lines to display simultaneously.
*/
this.chatLines = 20;
this.chatLinesNumber = 20;
/**
* Number of seconds after which chatmessages will disappear.
@@ -26,6 +26,41 @@ class ChatOverlay
this.chatMessages = [];
this.chatText = Engine.GetGUIObjectByName("chatText");
this.chatLines = Engine.GetGUIObjectByName("chatLines").children;
this.chatLinesNumber = Math.min(this.chatLinesNumber, this.chatLines.length);
}
displayChatMessages()
{
for (let i = 0; i < this.chatLinesNumber; ++i)
{
let chatMessage = this.chatMessages[i];
if (chatMessage && chatMessage.text)
{
// First scale line width to maximum size.
let lineSize = this.chatLines[i].size;
let height = lineSize.bottom - lineSize.top;
lineSize.top = i * height;
lineSize.bottom = lineSize.top + height;
lineSize.rright = 100;
this.chatLines[i].size = lineSize;
this.chatLines[i].caption = chatMessage.text;
// Now read the actual text width and scale the line width accordingly.
lineSize.rright = 0;
lineSize.right = lineSize.left + this.chatLines[i].getTextSize().width;
this.chatLines[i].size = lineSize;
if (chatMessage.callback)
this.chatLines[i].onPress = chatMessage.callback;
if (chatMessage.tooltip)
this.chatLines[i].tooltip = chatMessage.tooltip;
}
this.chatLines[i].hidden = !chatMessage || !chatMessage.text;
this.chatLines[i].ghost = !chatMessage || !chatMessage.callback;
}
}
/**
@@ -36,10 +71,10 @@ class ChatOverlay
this.chatMessages.push(chatMessage);
this.chatTimers.push(setTimeout(this.removeOldChatMessage.bind(this), this.chatTimeout * 1000));
if (this.chatMessages.length > this.chatLines)
if (this.chatMessages.length > this.chatLinesNumber)
this.removeOldChatMessage();
else
this.chatText.caption = this.chatMessages.join("\n");
this.displayChatMessages();
}
/**
@@ -48,7 +83,7 @@ class ChatOverlay
clearChatMessages()
{
this.chatMessages = [];
this.chatText.caption = "";
this.displayChatMessages();
for (let timer of this.chatTimers)
clearTimeout(timer);
@@ -64,6 +99,6 @@ class ChatOverlay
clearTimeout(this.chatTimers[0]);
this.chatTimers.shift();
this.chatMessages.shift();
this.chatText.caption = this.chatMessages.join("\n");
this.displayChatMessages();
}
}
@@ -193,10 +193,13 @@ var g_NotificationsTypes =
if (Engine.ConfigDB_GetValue("user", "gui.session.notifications.attack") !== "true")
return;
let entState = GetEntityState(notification.target);
addChatMessage({
"type": "attack",
"player": player,
"attacker": notification.attacker,
"target": notification.target,
"position": entState && entState.position,
"targetIsDomesticAnimal": notification.targetIsDomesticAnimal
});
},
@@ -40,8 +40,12 @@
<include file="gui/session/TimeNotificationOverlay.xml"/>
<!-- Chat messages -->
<object name="chatPanel" size="0 130 100% 100%-240" type="image" ghost="true" z="0" absolute="true">
<object name="chatText" size="3 1 100%-1 100%-1" type="text" style="chatPanelOverlay" ghost="true"/>
<object name="chatPanel" size="0 131 100% 100%-240" z="0" absolute="true">
<object name="chatLines">
<repeat count="20">
<object name="chatLine[n]" size="3 0 100% 17" type="button" style="chatPanelOverlay" tooltip_style="sessionToolTipBottomBold" ghost="true" hidden="true"/>
</repeat>
</object>
</object>
<include directory="gui/session/chat/"/>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<setup>
<icon name="icon_focusattacked"
sprite="stretched:session/icons/focus-attacked.png"
size="14 14"
/>
</setup>
@@ -237,7 +237,7 @@
font="sans-bold-stroke-14"
textcolor="white"
text_align="left"
text_valign="top"
text_valign="center"
/>
<style name="chatInput"