-
-
Notifications
You must be signed in to change notification settings - Fork 843
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature: [GS] Scriptable league tables #10001
Conversation
9680708
to
c7a4052
Compare
c7a4052
to
1493eb5
Compare
I haven't reviewed the code or tested this, but I think this is an excellent path forward from the current scoring system. As broken as it is, I agree with your decision to keep it as a fallback when no custom scoring is present. |
As owner of GS server I agree that whole system of goals should be reworked, I mean its 2022. This game should put more attention into multiplayer. |
1493eb5
to
b6ca514
Compare
Since no one commented on the api or naming I went on with what I had and finished the PR. |
b6ca514
to
e7b6843
Compare
Reimplementing the CityMania goal tables in the new league table system as it currently stands (with no header or footer) would mean losing the ability to have a detailed description of what the goal is or scores mean. For example, without a header or footer, the league table would only have a title of "Goal: 10,000 people", the elements, and nothing else. With a header, it can be used to show the full goal and what the scores mean. With a footer, it can be used to show something along the lines of "... and X more" if there are too many companies/entries to show at once. Therefore, league tables should (in this implementation) allow for a header and/or footer. |
I added header a footer. Doesn't look particularly nice but so is the rest of scriptable UI. P.S. Stupid github doesn't want to attach new screenshot for some reason :( |
9809cb8
to
ce2a814
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No issues in principle. Mostly nitpicks
src/league_gui.cpp
Outdated
|
||
class PerformanceLeagueWindow : public Window { | ||
private: | ||
GUIList<const Company*> companies; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this was in the original code, but why does there need to be a copy of the companies list stored within the window?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I understand it, because it's inconvenient to keep list constantly updated, so to avoid glitches due to resorting it stores a copy and updates it episodically with full redraw of the window.
} | ||
|
||
|
||
class ScriptLeagueWindow : public Window { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could do with some doxy comments throughout
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added some
}; | ||
|
||
typedef uint8 LeagueTableID; ///< ID of a league table | ||
struct LeagueTable; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels odd to have these forward declared in a header. Is that normal compared to other types?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was copying story_type.hpp
, seems pretty common.
|
||
/* static */ ScriptLeagueTable::LeagueTableID ScriptLeagueTable::New(Text *title, Text *header, Text *footer) | ||
{ | ||
CCountedPtr<Text> title_counter(title); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this feels very std::shared_ptr... but that's something for the future.
* | ||
* @param index Graph to show. | ||
* @return #CBF_NONE | ||
* Enum for the League Toolbar's and Graph Toolbar's related buttons. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not actually an enum. Could it be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly, but CTMN_*
in the same file isn't technically a enum either but is called so in the comment.
ce2a814
to
18331b2
Compare
3aee5f5
to
add83a4
Compare
src/toolbar_gui.cpp
Outdated
@@ -2020,7 +2057,7 @@ struct MainToolbarWindow : Window { | |||
case MTHK_STORY: ShowStoryBook(_local_company); break; | |||
case MTHK_GOAL: ShowGoalsList(_local_company); break; | |||
case MTHK_GRAPHS: ShowOperatingProfitGraph(); break; | |||
case MTHK_LEAGUE: ShowCompanyLeagueTable(); break; | |||
case MTHK_LEAGUE: ShowPerformanceLeagueTable(); break; // FIXME |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
69ac2aa
to
9097688
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Would appreciate another set of eyes on it
widest_width = std::max(widest_width, GetStringBoundingBox(STR_COMPANY_LEAGUE_COMPANY_NAME).width); | ||
} | ||
|
||
this->text_width = widest_width + WidgetDimensions::scaled.hsep_indent * 3; // Keep some extra spacing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiplying hsep_indent
by a magic number to create some new non-standard amount of space isn't particularly pretty. Is there another constant that could be used, or created?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does happen in other places: https://github.com/OpenTTD/OpenTTD/blob/master/src/cheat_gui.cpp#L244
Idk any better way to do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copy & paste of my changes too, it's basically "make some arbitrary space", which may or may not be equal in different places.
9097688
to
e2c18f4
Compare
e2c18f4
to
30da057
Compare
Default company league table came from the original game and has long lost its purpose since. As the base game has no goal it's kind of pointless to rank companies by some arbitrary rating that doesn't even facilitate good gameplay. So while adding goals to the game is the job of gamescripts, right now they have no way to change the league table mechanics having to misuse global goals for that purpose leading to player confusion.
So I designed a GS API for league tables based on the "league tables" of CityMania servers. As they're the most complex ones I've seen and cover all other use cases I know of, nicely showcasing:
So I kind of got it all working but before I go finish all the boring technical details I'd like to see what opinions there are on this PR in general and some details in particular:
Naming of things. Currently, I called the table itself LeagueTable and its elements (rows) LeagueTableElement like in story pages. But it seems kinda long and generic, should I just call them rows? Also, I added
Link
,LinkType
andLinkTargetID
types that currently are kind of out of the scope of LeagueTables but are only used by them. The idea is to eventually use them in other scriptable UI like goals or story book but I don't want to do that in this PR. So should I name them like LeagueTableLink for now? I'm also looking for better names for all the other stuff.Default league table and scoring. As I said, I don't see much point in keeping it in the game anymore. But in case someone feels strongly about it I kinda wanted to avoid removing it in this PR. So far I made it so that it shows default league menu options (league table, detailed rating, highscores) only if there are no custom league tables in the game. If there are it only shows the list of tables as GS author can implement highscores as a custom league table if they wish so and making custom rating details is just something I don't see possible without a full framework for custom UI.
Attributes. LeagueTable is quite simple and only has a title, header and footer.
LeagueTableElement though has a lot:
table
- id of the table it belongs torating
- hidden value used only for ordering elements in the table.score
- string with a visible score to show.text
- main text of the element (i.e. company name).link
-Link(target_type, target_id)
for the object to open when this element is clicked.So I separated the logical "score" used for sorting and the visual one because, as I already said, the score can be quite complex and I don't think the game should limit it to certain types. And yet it needs some value to use for sorting the elements.
GS API. Currently, I've added the
GSLeagueTable
class with the following methods:New(title, header, footer) -> LeagueTableID
- Add a new league table.NewElement(table, rating, company, text, score, link_type, link_target) -> LeagueTableElementID
- Add an element (row) to the table.UpdateElementData(element, company, text, link_type, link_target)
.UpdateElementScore(element, rating, score)
.RemoveElement(element)
.I decided to split updating into two methods as IMO score is updated much more often and in different places than data is.
TODO:
GS to test this (implements default league table in GS):
testleaguetable.zip