Page MenuHomeWildfire Games

Defeat reason
ClosedPublic

Authored by Silier on Jul 31 2017, 11:00 PM.
Tags
None
Subscribers
Restricted Owners Package
Restricted Owners Package
Restricted Owners Package
Tokens
"Like" token, awarded by Lionkanzen.

Details

Summary

The chat notification for win and defeat was updated:

player X has been defeated (resigned) in case of resignation
player X has been defeated (lost all workers) in conquestUnits
player X has been defeated (lost all structures) in conquestStructures
player X has been defeated (lost all structures and workers) in conquest
player X has been defeated (lost civic center) in survival of the fittest
player X has been defeated (lost hero) in regicide
player X has been defeated (relic captured) in relic game
player X has been defeated (wonder victory) in wonder game
player X has been defeated (treasure collected) in treasure islands

player X has won (allied victory) when last man standing is not enabled
player X has won (last player alive) if player is alone alive in the game
player X has won (wonder victory) in wonder game
player X has won (relic captured) in relic game
player X has won (treasure collected) in treasure islands

Test Plan

Run the game.

Notification should be displayed correctly in singleplayer and multiplayer.

Diff Detail

Repository
rP 0 A.D. Public Repository
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

Silier created this revision.Jul 31 2017, 11:00 PM
Owners added subscribers: Restricted Owners Package, Restricted Owners Package, Restricted Owners Package.Jul 31 2017, 11:00 PM
Lionkanzen added a subscriber: Lionkanzen.
Silier updated this revision to Diff 2991.Aug 1 2017, 2:17 PM

coding style
translateWithContext added
comments for translation removed

elexis added inline comments.Aug 1 2017, 3:08 PM
binaries/data/mods/public/maps/scripts/ConquestCommon.js
25 ↗(On Diff #2991)

Either JS doc /** for function headers or //, but this comment isn't needed because the variable name is sufficiently explanatory

26 ↗(On Diff #2991)

The defeatReason doesn't have to be determined, if if (index == -1).
We could make that an "early return", i.e. if index == -1 return, then determine the defeat reason, splice and set the state

31 ↗(On Diff #2991)

remove those braces { }, since they are not needed if there is only one statement and it's slightly quicker to read

38 ↗(On Diff #2991)

else if (

binaries/data/mods/public/simulation/components/EndGameManager.js
93 ↗(On Diff #2991)

In which situation is that called? We ought to have a string for every case

binaries/data/mods/public/simulation/components/Player.js
439 ↗(On Diff #2991)

no whitespace in empty lines (nor trailing whitespace)

build/svn_revision/svn_revision.txt
1 ↗(On Diff #2991)

(We can ignore this file when committing if it's too much trouble to get rid of this diff)

Silier updated this revision to Diff 2993.Aug 1 2017, 6:33 PM
Silier edited the summary of this revision. (Show Details)
Silier updated this revision to Diff 2994.Aug 1 2017, 9:26 PM
Silier edited the summary of this revision. (Show Details)

improved deciding of defeat reason in conquest, conquestStructure and conquestUnit

Silier updated this revision to Diff 2997.Aug 1 2017, 10:01 PM
elexis edited edge metadata.Aug 3 2017, 8:46 PM

The patch is satisfying, but it could be better.
Going back to the design perspective:

(1) Grouping messages

It'd be more readable if MarkPlayerAsWon and AlliedVictoryCheck only send one GUI message for the winners and one for the defeated players per reason.

So instead of:

player 1 has resigned.
player 2 has won (allied victory)
player 3 has won (allied victory)
player 4 has won (allied victory)
player 1 has resigned.
player 2, player3 and player 4 have won (allied victory)

And instead of

player 2 has won (relic victory)
player 3 has won (allied victory)
player 4 has won (allied victory)
player 1 has been defeated (relic victory).
player 2, player3 and player 4 have won (relic victory)
player 1 has been defeated (relic victory).

(2) has been defeated (%(reason)s)

12:26 < Angen> "player has been defeated (resigned)" or "player has been resign" ?
12:28 < elexis> "has resigned" seems better, but not sure if it would make that code ugly
12:28 < elexis> perhaps its better to pass the entire sentence in SetState
12:29 < elexis> this way the translators would also not be bound to the "something (Something else)" format for every victory /defeat type
12:33 < Angen> you suggest e.g. : cmpPlayer.setState("won","has been defeated (lost all workers)"); ?
12:34 < Angen> with the markfortranslation ofc
12:34 < Angen> ** "defeated",....
12:36 < elexis> besides the missing subject in that sentence, possibly

I still think the sentence in 12:33 is good (as in don't know a better phrasing), but I still think we should do what was mentioned in 12:28 and 12:29.
For the reader player1 has resigned. would be easier and more intuitive to read than player1 has been defeated (resigned)..

This string should be avoided because it forces both the english string and the translators to use that specific syntax for every possible victory / defeat reason.
`translate("%(player)s has been defeated (%(reason)s).")'

So instead of passing the reason as a half sentence and providing a translation context to supplement the comprehensiveness of the string, we could pass an entire sentence for every reason and give the english strings and translations thereof the freedom to provide a custom string for every reason.

So the sentence in the example at 12:33 would be written as

markForPluralTranslation("%(lastPlayer)s has won (relic victory).", "%(players)s and %(lastPlayer)s have won (relic victory)", number)

We'd also have the possibility to use something like that, but doesn't really convince me. Translators still have that freedom to remove the parentheses selectively independent for each string.

`%(players)s and %(lastPlayer)s have won the wonder victory.`

The players and lastPlayer variable should be something like seen in getLocalizedResourceAmounts of tooltips.js:

	return sprintf(translate("%(previousAmounts)s and %(lastAmount)s"), {
		// Translation: This comma is used for separating first to penultimate elements in an enumeration.
		"previousAmounts": amounts.join(translate(", ")),
		"lastAmount": lastAmount
	});

(3) No whitespace in empty lines, one space after a comma.

Silier updated this revision to Diff 3005.Aug 4 2017, 2:47 PM

grouping reasons

Silier updated this revision to Diff 3006.Aug 4 2017, 2:57 PM

correction

elexis added inline comments.Aug 4 2017, 4:18 PM
binaries/data/mods/public/gui/session/session.js
661 ↗(On Diff #3007)

Hm, letting the GUI chose the string "%(lastPlayer)s has resigned" means that the player could instead send the string "%(lastPlayer)s has won" or "[color=red]player 2 has left." f.e..

If the string would be saved in the simulation, then the player could only fake the resign bit.
In fact there isn't a use case in the public mod where resign would be false and I don't see one directly.
The one defeat cheat we have ùses cmpPlayer.SetState("defeated"); and we shouldn't implement 2 ways for the same cheat.
I don't see a use case for AI developers or mods (like delenda est) where this command would be useful either.
The "defeat-player" order in Commands.js already ignores the sent playerId and always defeats the player who sent the command, right?
So renaming "defeat-player" to "resign" would solve that and other issues with the same amount of code afaics.
In case someone comes in screeming that we needs the defeat command without resign, we can revert the two lines.

The mtnioned defeat cheat in Cheat.js is also missing a string.

elexis added inline comments.Aug 4 2017, 4:46 PM
binaries/data/mods/public/gui/session/messages.js
973 ↗(On Diff #3007)

The two functions now do the same chat message formatting, we only need one formatVictoryMessage function and only one entry in g_FormatChatMessage.

We can keep the two g_NotificationsTypes types, but the two affected GUI message handler functions are duplicate and could be merged in a new function called from these two GUI notification events.

984 ↗(On Diff #3007)

English strings and strings that determine GUI formatting should be translated. The sprintf however doesn't seem needed.

Also it would be a nice case for https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

How about

let players = msg.players.map(playerID => colorizePlayernameByID(playerID));
987 ↗(On Diff #3007)

translatePlural(msg.message.message, msg.message.pluralMessage, msg.message.pluralCount) afaics

989 ↗(On Diff #3007)

Copy over that penultimate translation comment from tooltips.js

Silier updated this revision to Diff 3010.Aug 4 2017, 11:13 PM
Silier edited the summary of this revision. (Show Details)
elexis accepted this revision.Aug 8 2017, 1:23 PM

Don't worry about the many changes. Someone who didn't look at the code prior to this can't know in advance.
It is a very good patch and you have done very well, always understood what I meant.
Good job, thanks for the patch!

binaries/data/mods/public/gui/session/messages.js
140 ↗(On Diff #3010)

That description doesn't tell us what's inside that variable. It's not straight-forward as the reader encounters player and allies

143 ↗(On Diff #3010)

The function should be defined where the other functions are, not in between these two big objects.

147 ↗(On Diff #3010)

(Hm, seems like there was a bug in the previous code. The guid isn't used as far as I can see. Since it's the network client identifier, the GUID should only be set if a player sends a chat.) Nuking this line

153 ↗(On Diff #3010)

In fact it looks like we can just push these two things to playerFinished. Renaming the latter to indicate that its called for multiple players now.

whitespace stuff

Also notice something? Since we now have one message for multiple defeats / victories, we also only have one sendLobbyPlayerlistUpdate call, which means we reduce useless traffic :-)

978 ↗(On Diff #3010)

msg.message.message is a bit awkward to read. Nicer to pass players and message

binaries/data/mods/public/gui/session/session.js
661 ↗(On Diff #3007)

playerId still unused

binaries/data/mods/public/maps/random/survivalofthefittest_triggers.js
348 ↗(On Diff #3010)

We can use newlines within the string, according to BuildRestrictions.js whose string shows up in the l10n directory

binaries/data/mods/public/maps/scenarios/treasure_islands.js
115 ↗(On Diff #3010)

markForPluralTranslation

binaries/data/mods/public/maps/scripts/CaptureTheRelic.js
156 ↗(On Diff #3010)

;

168 ↗(On Diff #3010)

missing %

relic captured -> relic victory or Capture the Relic

binaries/data/mods/public/maps/scripts/ConquestStructures.js
4 ↗(On Diff #3010)

(Only the ConquestCritical structures are relevant, but explaining that in the string would make it ugly)

binaries/data/mods/public/maps/scripts/TriggerHelper.js
119 ↗(On Diff #3010)

This one must explain the that those reasons are functions mapping to a plural string (since this file is supposed to make things easier for modders)

129 ↗(On Diff #3010)

Even more a comment is needed now, because the win function needs a function, this one gets the string straight away!

binaries/data/mods/public/maps/scripts/WonderVictory.js
79 ↗(On Diff #3010)

nice function for the future.
We could do all sorts of stuff here, cheering, playing some cinematic path, playing a special soundfile, marking some objectives as done, informing the AI,...

92 ↗(On Diff #3010)

At least in this revision of the patch, we use the variables only once, so can be inlined + \n

binaries/data/mods/public/simulation/components/EndGameManager.js
31 ↗(On Diff #3010)

I'm not too happy about "last players alive" nor "allied victory" being shown if all enemies are defeated. It feels more like "Conquest" to me.

62 ↗(On Diff #3010)

alliesNotification -> winners, or winningPlayers
enemiesNotification -> losers, or defeatedPlayers

86 ↗(On Diff #3010)

if( -> if (

if (alliesNotification.length) sufficient

88 ↗(On Diff #3010)

We need the cmpGUIInterface only once, so it can be moved outside of the if's and outside of the loop..

(Some negligible thought:
Having "player 1 has won (wonder victory)" and "player2, player3 have won (allied victory)" seems more intuitive, but makes no sense for relic games.
Since one might argue that despite only one player having the relevant wonder, the other players might still have had to pay the same share to achieve victory, using this string makes sense in the wonder victory case too.
There might be other modes where only one player can win.
F.e. the player with most resources after 15min or the first player who found one treasure wins, while the others win by allied victory.
Don't see the reason to add that complexity now however.)

144 ↗(On Diff #3010)

unneeded newline

156 ↗(On Diff #3010)

alliesNotification and allies are the same, no?

162 ↗(On Diff #3010)

cmpGUIInterface already defined above

binaries/data/mods/public/simulation/components/Player.js
398 ↗(On Diff #3010)

A function comment is crucial here.
The users of this function have to know that they can use undefined or a function mapping from n to markForPluralString

453 ↗(On Diff #3010)

players are the ones who we send the message to, It's kind of pointless historical garbage, but not going to clean it in this diff.
Unfortunately this forces us to use allies, even though the defeated enemies might not be allies. Meh

binaries/data/mods/public/simulation/helpers/Commands.js
444 ↗(On Diff #3010)

You had asked whether we could sometimes send a plural string, and other times (like here) only a singular string.

It's possible in fact, quoting from input.js:

						if (result.pluralMessage)
							message = translatePlural(result.message, result.pluralMessage, result.pluralCount);
						else
							message = translate(message);
This revision is now accepted and ready to land.Aug 8 2017, 1:23 PM
This revision was automatically updated to reflect the committed changes.