Merged uni's branch with trunk. No guarantee that everything works ;)

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@14620 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk
2013-12-03 23:02:06 +00:00
217 changed files with 13898 additions and 4164 deletions

17
data/achievements.xml Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0"?>
<achievements>
<achievement id="1" type="map" title="Christoffel Columbus" description="Play every official track at least once." >
<entry key="farm" goal="1"/>
<entry key="scotland" goal="1"/>
<entry key="lighthouse" goal="1"/>
<entry key="sandtrack" goal="1"/>
<entry key="olivermath" goal="1"/>
<entry key="subsea" goal="1"/>
<entry key="mansion" goal="1"/>
<entry key="minigolf" goal="1"/>
<entry key="hacienda" goal="1"/>
<entry key="jungle" goal="1"/>
</achievement>
<achievement id="2" type="single" goal="10" title="Strike!" description="Hit 10 karts with a bowling-ball." />
</achievements>

View File

@@ -4,7 +4,7 @@
<icon id="logo" align="center" proportion="5" width="100%" icon="gui/logo.png"/>
<buttonbar id="menu_toprow" proportion="3" width="75%" align="center">
<buttonbar id="menu_toprow" proportion="3" width="90%" align="center">
<icon-button id="story" width="128" height="128"
icon="gui/menu_story.png" focus_icon="gui/menu_story_focus.png"
I18N="Main menu button" text="Story Mode"/>
@@ -14,6 +14,9 @@
<icon-button id="multiplayer" width="128" height="128"
icon="gui/menu_multi.png" focus_icon="gui/menu_multi_focus.png"
I18N="Main menu button" text="Multiplayer"/>
<icon-button id="online" width="128" height="128"
icon="gui/menu_online.png" focus_icon="gui/menu_online_focus.png"
I18N="Main menu button" text="Online"/>
<icon-button id="addons" width="128" height="128"
icon="gui/menu_addons.png" focus_icon="gui/menu_addons_focus.png"
I18N="Main menu button" text="Addons"/>

BIN
data/gui/menu_online.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@@ -0,0 +1,47 @@
<stkgui>
<div x="2%" y="5%" width="96%" height="90%" layout="vertical-row" >
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the change password dialog" text="Password Change"/>
<spacer height="40" width="50">
<div width="80%" align="center" layout="vertical-row" height="fit" >
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the change password dialog" text="Current Password"/>
<textbox proportion="2" height="fit" id="current_password" I18N="In the change password dialog"/>
</div>
<spacer height="20" width="20">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the change password dialog" text="New Password"/>
<textbox proportion="2" height="fit" id="new_password1" I18N="In the change password dialog"/>
</div>
<spacer height="20" width="20">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the change password dialog" text="Confirm"/>
<textbox proportion="2" height="fit" id="new_password2" I18N="In the change password dialog"/>
</div>
</div>
<spacer height="20" width="50">
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true" text=""/>
<spacer height="20" width="50">
<buttonbar id="options" width="90%" height="16%" align="center">
<icon-button id="submit" width="64" height="64" icon="gui/green_check.png"
I18N="In the change password dialog" text="Submit" label_location="bottom"/>
<icon-button id="cancel" width="64" height="64" icon="gui/main_quit.png"
I18N="In the change password dialog" text="Close" label_location="bottom"/>
</buttonbar>
</div>
</stkgui>

View File

@@ -0,0 +1,36 @@
<stkgui>
<div x="0" y="0" width="100%" height="100%" layout="vertical-row" >
<header text_align="center" width="80%" align="center" I18N="In the create server screen" text="Server Creation"/>
<spacer height="15" width="10"/>
<box proportion="4" width="90%" layout="vertical-row" align="center">
<div width="90%" align="center" layout="vertical-row" y="2%" height="96%">
<div width="100%" align="center" layout="vertical-row" height="fit" >
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the create server screen" text="Name of the server"/>
<textbox proportion="1" id="name" I18N="In the create server screen"/>
</div>
<spacer height="20" width="20">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the create server screen" text="Max. number of players"/>
<gauge id="max_players" proportion="1" min_value="2" max_value="12"/>
</div>
</div>
<label id="info" proportion="1" width="100%" align="center" text_align="center" word_wrap="true" text=""/>
<buttonbar id="options" x="0" y="0" width="25%" height="12%" align="center">
<icon-button id="create" width="64" height="64" icon="gui/green_check.png"
I18N="Main menu button" text="Create" label_location="bottom"/>
<icon-button id="cancel" width="64" height="64" icon="gui/main_quit.png"
I18N="Main menu button" text="Cancel" label_location="bottom"/>
</buttonbar>
</div>
</box>
<spacer height="15" width="10"/>
</div>
</stkgui>

View File

@@ -0,0 +1,51 @@
<stkgui>
<div x="0" y="0" width="100%" height="100%" layout="vertical-row" >
<header text_align="center" width="80%" align="center" I18N="In networking lobby" text="Lobby"/>
<spacer height="15" width="10"/>
<div proportion="1" x="2%" width="96%" layout="vertical-row">
<div width="100%" proportion="2" layout="horizontal-row">
<box id="info" proportion="2" height="100%" layout="vertical-row">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the networking lobby" text="Server name :"/>
<label proportion="2" text_align="left" id="server_name" text=""/>
</div>
</box>
<spacer width="20" height="20"/>
<box proportion="1" height="100%" layout="vertical-row">
<list id="players" width="100%" height="100%"/>
</box>
</div>
<spacer width="20" height="20"/>
<div width="100%" proportion="1" layout="horizontal-row">
<box proportion="2" height="100%" layout="vertical-row">
<list id="chat" width="100%" height="100%"/>
</box>
<spacer width="20" height="20"/>
<box id="actions" proportion="1" height="100%" layout="vertical-row">
<label I18N="In networking lobby" word_wrap="true" text="actions" align="center" text-align="center"/>
</box>
</div>
</div>
<spacer width="10" height="7%"/>
<bottombar x="2%" width="96%" height="10%" layout="horizontal-row">
<label text_align="left" align="center" height="100%" id="online_status" proportion="1" text=""/>
<spacer width="10" height="10" />
<buttonbar id="menu_bottomrow" x="0" y="0" width="20%" height="100%" align="center">
<icon-button id="exit" width="64" height="64" icon="gui/main_quit.png" extend_label="50"
I18N="Main menu button" text="Exit" label_location="hover"/>
</buttonbar>
</bottombar>
</div>
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
</stkgui>

View File

@@ -0,0 +1,32 @@
<stkgui>
<div x="0" y="0" width="100%" height="100%" layout="vertical-row" >
<header text_align="center" width="80%" align="center" I18N="In the lobby settings screen" text="Lobby Settings"/>
<spacer height="15" width="10"/>
<box proportion="4" width="90%" layout="vertical-row" align="center">
<div width="90%" align="center" layout="vertical-row" height="fit" >
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the lobby settings screen" text="Name of the server"/>
<textbox proportion="2" id="name" I18N="In the login dialog"/>
</div>
<spacer height="20" width="20">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the lobby settings screen" text="Max. number of players"/>
<gauge id="max_players" proportion="2" min_value="2" max_value="12"/>
</div>
</div>
</box>
<spacer width="10" height="7%"/>
<bottombar x="2%" width="96%" height="10%" layout="horizontal-row">
</bottombar>
</div>
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
</stkgui>

View File

@@ -0,0 +1,59 @@
<stkgui>
<div x="2%" y="5%" width="96%" height="90%" layout="vertical-row" >
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the login dialog" text="Sign in"/>
<spacer height="25" width="50">
<label id="message" proportion="2" width="90%" align="center" text_align="left" word_wrap="true" text=""/>
<spacer height="40" width="50">
<div width="80%" align="center" layout="vertical-row" height="fit" >
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the login dialog" text="Username"/>
<textbox proportion="2" height="fit" id="username" I18N="In the login dialog"/>
</div>
<spacer height="20" width="20">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the login dialog" text="Password"/>
<textbox x="5" proportion="2" height="fit" id="password" I18N="In the login dialog"/>
</div>
<spacer height="20" width="20">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the login dialog" text="Stay signed in"/>
<div proportion="2" height="100%" layout="horizontal-row">
<checkbox width="fit" height="fit" id="remember" I18N="In the login dialog"/>
</div>
</div>
</div>
<spacer height="20" width="50">
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true" text=""/>
<spacer height="20" width="50">
<buttonbar id="options" width="90%" height="13%" align="center">
<icon-button id="sign_in" width="64" height="64" icon="gui/green_check.png"
I18N="Login dialog" text="Sign In" label_location="bottom"/>
<icon-button id="recovery" width="64" height="64" icon="gui/main_help.png"
I18N="Login dialog" text="Recovery" label_location="bottom"/>
<icon-button id="register" width="64" height="64" icon="gui/tutorial.png"
I18N="Login dialog" text="Register" label_location="bottom"/>
<icon-button id="as_guest" width="64" height="64" icon="gui/main_about.png"
I18N="Login dialog" text="As guest" label_location="bottom"/>
<icon-button id="cancel" width="64" height="64" icon="gui/main_quit.png"
I18N="Login dialog" text="Close" label_location="bottom"/>
</buttonbar>
</div>
</stkgui>

View File

@@ -0,0 +1,51 @@
<stkgui>
<div x="0" y="0" width="100%" height="100%" layout="vertical-row" >
<header text_align="center" width="80%" align="center" I18N="In the online multiplayer screen" text="Online Multiplayer"/>
<spacer height="15" width="10"/>
<box proportion="4" width="90%" layout="vertical-row" align="center">
<div x="2%" y="2%" width="96%" height="96%" layout="vertical-row" id="outer_box" >
<label I18N="In the online multiplayer screen" proportion="4" word_wrap="true" text=
"Here will come some information.. or statistics.. or whatever. Yet to be filled in! It will change depending on state. And I'd also like a close button at the right top.
" align="center"/>
</div>
</box>
<buttonbar id="menu_toprow" proportion="3" width="90%" align="center">
<icon-button id="quick_play" width="128" height="128"
icon="gui/online/menu_quick_play.png" focus_icon="gui/online/menu_quick_play_hover.png"
I18N="Online menu button" text="Quick Play"/>
<icon-button id="find_server" width="128" height="128"
icon="gui/online/menu_find_server.png" focus_icon="gui/online/menu_find_server_hover.png"
I18N="Online menu button" text="Find Server"/>
<icon-button id="create_server" width="128" height="128"
icon="gui/online/menu_create_server.png" focus_icon="gui/online/menu_create_server_hover.png"
I18N="Online menu button" text="Create Server"/>
</buttonbar>
<spacer width="10" height="7%"/>
<bottombar x="2%" width="96%" height="10%" layout="horizontal-row">
<label text_align="left" align="center" height="100%" id="online_status" proportion="1" text=""/>
<spacer width="10" height="10" />
<buttonbar id="menu_bottomrow" x="0" y="0" width="12%" height="100%" align="center">
<icon-button id="sign_in" width="64" height="64" icon="gui/main_about.png" extend_label="50"
I18N="Online menu button" text="Sign In" label_location="hover"/>
<icon-button id="register" width="64" height="64" icon="gui/tutorial.png" extend_label="75"
I18N="Online menu button" text="Register" label_location="hover"/>
<icon-button id="profile" width="64" height="64" icon="gui/green_check.png" extend_label="50"
I18N="Online menu button" text="Profile" label_location="hover"/>
<icon-button id="sign_out" width="64" height="64" icon="gui/main_quit.png" extend_label="70"
I18N="Online menu button" text="Sign Out" label_location="hover"/>
</buttonbar>
</bottombar>
</div>
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
</stkgui>

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@@ -0,0 +1,19 @@
<stkgui>
<div x="2%" y="5%" width="96%" height="85%" layout="vertical-row" >
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true" text=""/>
<spacer height="20" width="50">
<buttonbar id="options" width="90%" height="30%" align="center">
<icon-button id="view" width="64" height="64" icon="gui/difficulty_medium.png"
I18N="User info dialog" text="View" label_location="bottom"/>
<icon-button id="cancel" width="64" height="64" icon="gui/main_quit.png"
I18N="User info dialog" text="Close" label_location="bottom"/>
</buttonbar>
</div>
</stkgui>

View File

@@ -0,0 +1,23 @@
<stkgui>
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
<div x="1%" y="1%" width="98%" height="98%" layout="vertical-row" >
<header id="title" text_align="center" width="80%" align="center" text="..."/>
<spacer height="25" width="10"/>
<tabs id="profile_tabs" height="10%" max_height="110" x="2%" width="98%" align="center">
<icon-button id="tab_overview" width="128" height="128" icon="gui/options_ui.png" />
<icon-button id="tab_friends" width="128" height="128" icon="gui/options_players.png"/>
<icon-button id="tab_achievements" width="128" height="128" icon="gui/options_players.png" I18N="Section in the profile menu" text="Achievements"/>
<icon-button id="tab_settings" width="128" height="128" icon="gui/main_options.png"/>
</tabs>
<box proportion="1" width="100%" layout="vertical-row" padding="6">
<list id="achievements_list" x="0" y="0" width="100%" height="100%"/>
</box>
</div>
</stkgui>

View File

@@ -0,0 +1,37 @@
<stkgui>
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
<div x="1%" y="1%" width="98%" height="98%" layout="vertical-row" >
<header id="title" text_align="center" width="80%" align="center" text="..."/>
<spacer height="25" width="10"/>
<tabs id="profile_tabs" height="10%" max_height="110" x="2%" width="98%" align="center">
<icon-button id="tab_overview" width="128" height="128" icon="gui/options_ui.png" />
<icon-button id="tab_friends" width="128" height="128" icon="gui/options_players.png" I18N="Section in the profile menu" text="Friends"/>
<icon-button id="tab_achievements" width="128" height="128" icon="gui/options_players.png"/>
<icon-button id="tab_settings" width="128" height="128" icon="gui/main_options.png"/>
</tabs>
<box proportion="1" width="100%" layout="vertical-row" padding="6">
<list id="friends_list" x="0" y="0" width="100%" height="100%"/>
</box>
<div id="search_div" height="fit" width="100%" layout="vertical-row">
<spacer width="10" height="10"/>
<box height="fit" width="100%" layout="vertical-row">
<label height="fit" text_align="left" I18N="Profile friends" text="Look for more friends:"/>
<spacer width="10" height="10"/>
<div height="fit" width="100%" layout="horizontal-row" align="center">
<textbox id="search_box" proportion="1" height="fit"/>
<spacer width="10" height="100%"/>
<button id="search_button" height="100%" width="fit" text="Search" />
</div>
</box>
</div>
</div>
</stkgui>

View File

@@ -0,0 +1,25 @@
<stkgui>
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
<div x="1%" y="1%" width="98%" height="98%" layout="vertical-row" >
<header id="title" text_align="center" width="80%" align="center" text="..."/>
<spacer height="25" width="10"/>
<tabs id="profile_tabs" height="10%" max_height="110" x="2%" width="98%" align="center">
<icon-button id="tab_overview" width="128" height="128" icon="gui/options_ui.png" I18N="Section in the profile menu" text="Overview"/>
<icon-button id="tab_friends" width="128" height="128" icon="gui/options_players.png" />
<icon-button id="tab_achievements" width="128" height="128" icon="gui/options_players.png"/>
<icon-button id="tab_settings" width="128" height="128" icon="gui/main_options.png"/>
</tabs>
<box proportion="1" width="100%" layout="vertical-row">
<div x="1%" y="2%" width="98%" height="96%" layout="vertical-row" >
</div>
</box>
</div>
</stkgui>

View File

@@ -0,0 +1,29 @@
<stkgui>
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
<div x="1%" y="1%" width="98%" height="98%" layout="vertical-row" >
<header id="title" text_align="center" width="80%" align="center" text="..."/>
<spacer height="25" width="10"/>
<tabs id="profile_tabs" height="10%" max_height="110" x="2%" width="98%" align="center">
<icon-button id="tab_overview" width="128" height="128" icon="gui/options_ui.png"/>
<icon-button id="tab_friends" width="128" height="128" icon="gui/options_players.png" />
<icon-button id="tab_achievements" width="128" height="128" icon="gui/options_players.png"/>
<icon-button id="tab_settings" width="128" height="128" icon="gui/main_options.png" I18N="Section in the profile menu" text="Account Settings"/>
</tabs>
<box proportion="1" width="100%" layout="vertical-row">
<div x="1%" y="2%" width="98%" height="96%" layout="vertical-row" >
<div width="fit" height="fit" layout="horizontal-row" >
<label proportion="1" height="fit" text_align="left" I18N="In the online account settings screen" text="Password :"/>
<spacer width="20" height="1"/>
<button id="change_password_button" height="100%" width="fit" text="Change" />
</div>
</div>
</box>
</div>
</stkgui>

View File

@@ -0,0 +1,23 @@
<stkgui>
<div x="2%" y="5%" width="96%" height="90%" layout="vertical-row" >
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the registration dialog' dialog" text="Account Recovery"/>
<spacer height="20" width="50">
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true" I18N="In the registration dialog"
text="You will receive an email with further instructions on how to reset your password. Please be patient and be sure to check your spam folder."/>
<spacer height="20" width="50">
<buttonbar id="options" width="25%" height="15%" align="center">
<icon-button id="cancel" width="64" height="64" icon="gui/green_check.png"
I18N="Registration dialog" text="Close" label_location="none"/>
</buttonbar>
</div>
</stkgui>

View File

@@ -0,0 +1,46 @@
<stkgui>
<div x="2%" y="5%" width="96%" height="90%" layout="vertical-row" >
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the recovery dialog' dialog" text="Account Recovery"/>
<spacer height="20" width="50">
<label id="message" proportion="2" width="90%" align="center" text_align="left" word_wrap="true"
text="Fill in the username and email address you supplied at registration to be able to reset your password."/>
<spacer height="40" width="50">
<div width="80%" align="center" layout="vertical-row" height="fit">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the recovery dialog" text="Username"/>
<textbox proportion="2" id="username" I18N="In the recovery dialog"/>
</div>
<spacer height="20" width="20">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the recovery dialog" text="Email"/>
<textbox proportion="2" id="email" I18N="In the recovery dialog"/>
</div>
</div>
<spacer height="20" width="50">
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true"
I18N="In the recovery" text=""/>
<spacer height="20" width="50">
<buttonbar id="options" width="25%" proportion="1" align="center">
<icon-button id="submit" width="64" height="64" icon="gui/green_check.png"
I18N="Registration dialog" text="Submit" label_location="none"/>
<icon-button id="cancel" width="64" height="64" icon="gui/main_quit.png"
I18N="Registration dialog" text="Cancel" label_location="none"/>
</buttonbar>
</div>
</stkgui>

View File

@@ -0,0 +1,23 @@
<stkgui>
<div x="2%" y="4%" width="96%" height="92%" layout="vertical-row" >
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the registration dialog' dialog" text="Registration Complete"/>
<spacer height="25" width="50">
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true" I18N="In the registration dialog"
text="You will receive an email with further instructions regarding account activation. Please be patient and be sure to check your spam folder."/>
<spacer height="20" width="50">
<buttonbar id="options" width="25%" height="14%" align="center">
<icon-button id="cancel" width="64" height="64" icon="gui/green_check.png"
I18N="Registration dialog" text="Close" label_location="none"/>
</buttonbar>
</div>
</stkgui>

View File

@@ -0,0 +1,61 @@
<stkgui>
<div x="2%" y="4%" width="96%" height="92%" layout="vertical-row" >
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the registration dialog' dialog" text="Registration"/>
<spacer height="25" width="50">
<div width="80%" align="center" layout="vertical-row" height="fit">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the registration dialog" text="Username"/>
<textbox proportion="2" height="fit" id="username" I18N="In the registration dialog"/>
</div>
<spacer height="20" width="20">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the registration dialog" text="Password"/>
<textbox proportion="2" height="fit" id="password" I18N="In the registration dialog"/>
</div>
<spacer height="20" width="20">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the registration dialog" text="Confirm"/>
<textbox proportion="2" height="fit" id="password_confirm" I18N="In the registration dialog"/>
</div>
<spacer height="20" width="20">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the registration dialog" text="Email"/>
<textbox proportion="2" height="fit" id="email" I18N="In the registration dialog"/>
</div>
<spacer height="20" width="20">
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" height="100%" text_align="left" I18N="In the registration dialog" text="Confirm"/>
<textbox proportion="2" height="fit" id="email_confirm" I18N="In the registration dialog"/>
</div>
</div>
<spacer height="20" width="50">
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true"
I18N="In the registration dialog" text="You don't need to register if you have a STK Addons account!"/>
<spacer height="20" width="50">
<buttonbar id="options" width="25%" height="14%" align="center">
<icon-button id="next" width="64" height="64" icon="gui/green_check.png"
I18N="Registration dialog" text="Next" label_location="none"/>
<icon-button id="cancel" width="64" height="64" icon="gui/main_quit.png"
I18N="Registration dialog" text="Cancel" label_location="none"/>
</buttonbar>
</div>
</stkgui>

View File

@@ -0,0 +1,39 @@
<stkgui>
<div x="2%" y="4%" width="96%" height="92%" layout="vertical-row" >
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the registration dialog' dialog" text="Terms and Agreement"/>
<spacer height="25" width="50">
<box proportion="5" width="90%" align="center" layout="vertical-row" padding="8">
<list id="terms" x="0" y="0" width="100%" height="100%"/>
</box>
<div align="center" width="fit" height="fit" layout="horizontal-row" >
<label text_align="center" align="center" I18N="In the registration dialog" word_wrap="true"
text="I agree to the above terms and am 13 years or older. "/>
<checkbox id="accepted" I18N="In the registration dialog"/>
</div>
<spacer height="20" width="50">
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true"
I18N="In the registration dialog" text=""/>
<spacer height="20" width="50">
<buttonbar id="options" width="45%" height="14%" align="center">
<icon-button id="previous" width="64" height="64" icon="gui/back.png"
I18N="Registration dialog" text="Previous" label_location="bottom"/>
<icon-button id="next" width="64" height="64" icon="gui/green_check.png"
I18N="Registration dialog" text="Submit" label_location="bottom"/>
<icon-button id="cancel" width="64" height="64" icon="gui/main_quit.png"
I18N="Registration dialog" text="Cancel" label_location="bottom"/>
</buttonbar>
</div>
</stkgui>

View File

@@ -0,0 +1,33 @@
<stkgui>
<div x="2%" y="5%" width="96%" height="85%" layout="vertical-row" >
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the server info dialog' dialog" text="Server Info"/>
<spacer height="20" width="50">
<div width="80%" align="center" layout="vertical-row" height="fit" >
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="In the server info dialog" text="Name"/>
<label id="name" proportion="2" text_align="left" text=""/>
</div>
</div>
<spacer height="20" width="50">
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true" text=""/>
<spacer height="20" width="50">
<buttonbar id="options" width="90%" height="20%" align="center">
<icon-button id="join" width="64" height="64" icon="gui/green_check.png"
I18N="Login dialog" text="Join" label_location="bottom"/>
<icon-button id="cancel" width="64" height="64" icon="gui/main_quit.png"
I18N="Login dialog" text="Cancel" label_location="bottom"/>
</buttonbar>
</div>
</stkgui>

View File

@@ -0,0 +1,17 @@
<stkgui>
<div x="0%" y="0%" width="100%" height="98%" layout="vertical-row" >
<div x="0" y="0" width="100%" layout="horizontal-row" height="8%">
<icon-button id="back" height="100%" icon="gui/back.png"/>
<header text_align="center" proportion="1" text="Server Selection" align="center"/>
<icon-button id="reload" height="90%" icon="gui/restart.png"/>
</div>
<box proportion="1" width="98%" align="center" layout="vertical-row" padding="6">
<list id="server_list" x="0" y="0" width="100%" height="100%"/>
</box>
</div>
</stkgui>

View File

@@ -0,0 +1,41 @@
<stkgui>
<div x="2%" y="5%" width="96%" height="85%" layout="vertical-row" >
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="User info dialog' dialog" text="User Info"/>
<spacer height="20" width="50">
<div width="80%" align="center" layout="vertical-row" height="fit" >
<div width="100%" height="fit" layout="horizontal-row" >
<label proportion="1" text_align="left" I18N="User info dialog" text="Name"/>
<label id="name" proportion="2" text_align="left" text=""/>
</div>
</div>
<spacer height="20" width="50">
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true" text=""/>
<spacer height="20" width="50">
<buttonbar id="options" width="90%" height="20%" align="center">
<icon-button id="remove" width="64" height="64" icon="gui/package-uninstall.png"
I18N="User info dialog" text="Remove" label_location="bottom"/>
<icon-button id="friend" width="64" height="64" icon="gui/main_help.png"
I18N="User info dialog" text="Add Friend" label_location="bottom"/>
<icon-button id="accept" width="64" height="64" icon="gui/green_check.png"
I18N="User info dialog" text="Accept" label_location="bottom"/>
<icon-button id="decline" width="64" height="64" icon="gui/red_mark.png"
I18N="User info dialog" text="Decline" label_location="bottom"/>
<icon-button id="enter" width="64" height="64" icon="gui/difficulty_medium.png"
I18N="User info dialog" text="View" label_location="bottom"/>
<icon-button id="cancel" width="64" height="64" icon="gui/main_quit.png"
I18N="User info dialog" text="Close" label_location="bottom"/>
</buttonbar>
</div>
</stkgui>

View File

@@ -0,0 +1,24 @@
<stkgui>
<icon-button id="back" x="0" y="0" height="8%" icon="gui/back.png"/>
<div x="1%" y="0%" width="98%" height="99%" layout="vertical-row" >
<header text_align="center" height="fit" text="User search" align="center"/>
<spacer width="10" height="10"/>
<div height="fit" width="100%" layout="horizontal-row" align="center">
<textbox id="search_box" height="fit" proportion="1" height="100%"/>
<spacer width="10" height="10"/>
<button id="search_button" height="100%" width="fit" text="Search" />
</div>
<spacer width="10" height="10"/>
<box proportion="1" width="100%" align="center" layout="vertical-row" padding="6">
<list id="user_list" x="0" y="0" width="100%" height="100%"/>
</box>
</div>
</stkgui>

View File

@@ -0,0 +1,27 @@
<stkgui>
<div x="2%" y="5%" width="96%" height="90%" layout="vertical-row" >
<header id="title" width="96%" height="fit" text_align="center" word_wrap="true"
I18N="In the vote dialog' dialog" text="Vote"/>
<spacer height="20" width="50">
<label id="info" proportion="1" width="90%" align="center" text_align="center" word_wrap="true" text=""/>
<spacer height="20" width="50">
<div width="90%" height="64" align="center" layout="vertical-row" >
<ratingbar id="rating" align="center" height="64" width="192"/>
</div>
<spacer height="40" width="50">
<buttonbar id="options" width="25%" height="20%" align="center">
<icon-button id="cancel" width="64" height="64" icon="gui/main_quit.png"
I18N="Vote dialog" text="Close" label_location="none"/>
</buttonbar>
</div>
</stkgui>

View File

@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDYDCCAsmgAwIBAgIJAKYVnmvPe6cJMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNV
BAYTAkZSMQ8wDQYDVQQIEwZGcmFuY2UxEjAQBgNVBAcTCU1hcnNlaWxsZTEuMCwG
A1UEChMlVHV4RmFtaWx5Lm9yZyBub24tcHJvZml0IG9yZ2FuaXphdGlvbjEaMBgG
A1UEAxMRd2ViLnR1eGZhbWlseS5uZXQwHhcNMDgwNTE0MjMzMDI3WhcNMTgwNTEy
MjMzMDI3WjB+MQswCQYDVQQGEwJGUjEPMA0GA1UECBMGRnJhbmNlMRIwEAYDVQQH
EwlNYXJzZWlsbGUxLjAsBgNVBAoTJVR1eEZhbWlseS5vcmcgbm9uLXByb2ZpdCBv
cmdhbml6YXRpb24xGjAYBgNVBAMTEXdlYi50dXhmYW1pbHkubmV0MIGfMA0GCSqG
SIb3DQEBAQUAA4GNADCBiQKBgQCqCWPTYrW59LfzUtMgUFIse9ErIytmnNyVbzk6
11Zj0OTMuCp9ijHW47jqSp7OaOR7X5XmNyhltnidS7elXtVb/jZOINRzdejmLRWs
qBsnvWlab6kx+/u0kLAFH0w6s4Kg2K2s1eHtyid2IZLb+Xl29NGf+C6bRnUq9Bh2
6DF93QIDAQABo4HlMIHiMB0GA1UdDgQWBBSHuse3FoUQ1asK7+4YJ7FxH3tztzCB
sgYDVR0jBIGqMIGngBSHuse3FoUQ1asK7+4YJ7FxH3tzt6GBg6SBgDB+MQswCQYD
VQQGEwJGUjEPMA0GA1UECBMGRnJhbmNlMRIwEAYDVQQHEwlNYXJzZWlsbGUxLjAs
BgNVBAoTJVR1eEZhbWlseS5vcmcgbm9uLXByb2ZpdCBvcmdhbml6YXRpb24xGjAY
BgNVBAMTEXdlYi50dXhmYW1pbHkubmV0ggkAphWea897pwkwDAYDVR0TBAUwAwEB
/zANBgkqhkiG9w0BAQUFAAOBgQBYHLb4pjL7+xTk066JffNe1uCi2xXL93tsuphZ
6LVZkd3y4uIp9yayhUocOws8jptJHtr4TEV5AxS34B89AJgVERcj86K/RVSSwApO
g+ONYIyJ+Xdipdby6TIER+EgQxQJw1cxrMS3zzn7SNuo04CexqOTd5LUrtQJ/dOI
LPEqhw==
-----END CERTIFICATE-----

BIN
doc/protocols.xls Normal file

Binary file not shown.

View File

@@ -49,7 +49,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL
memset (host -> peers, 0, peerCount * sizeof (ENetPeer));
host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM);
if (host -> socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host -> socket, address) < 0))
if (host -> socket == ENET_SOCKET_NULL || (enet_socket_bind (host -> socket, address) < 0 && address != NULL))
{
if (host -> socket != ENET_SOCKET_NULL)
enet_socket_destroy (host -> socket);

View File

@@ -1,5 +1,9 @@
# Generated by ./update_file_list.sh. Do not edit this file manually.
set(STK_SOURCES
src/achievements/achievement.cpp
src/achievements/achievement_info.cpp
src/achievements/achievements_manager.cpp
src/achievements/achievements_slot.cpp
src/addons/addon.cpp
src/addons/addons_manager.cpp
src/addons/inetwork_http.cpp
@@ -63,6 +67,7 @@ src/graphics/wind.cpp
src/guiengine/abstract_state_manager.cpp
src/guiengine/abstract_top_level_container.cpp
src/guiengine/CGUISpriteBank.cpp
src/guiengine/dialog_queue.cpp
src/guiengine/engine.cpp
src/guiengine/event_handler.cpp
src/guiengine/layout_manager.cpp
@@ -75,6 +80,7 @@ src/guiengine/widget.cpp
src/guiengine/widgets/bubble_widget.cpp
src/guiengine/widgets/button_widget.cpp
src/guiengine/widgets/CGUIEditBox.cpp
src/guiengine/widgets/CGUISTKListBox.cpp
src/guiengine/widgets/check_box_widget.cpp
src/guiengine/widgets/dynamic_ribbon_widget.cpp
src/guiengine/widgets/icon_button_widget.cpp
@@ -116,6 +122,7 @@ src/karts/controller/ai_base_controller.cpp
src/karts/controller/ai_properties.cpp
src/karts/controller/controller.cpp
src/karts/controller/end_controller.cpp
src/karts/controller/network_player_controller.cpp
src/karts/controller/player_controller.cpp
src/karts/controller/skidding_ai.cpp
src/karts/explosion_animation.cpp
@@ -147,15 +154,47 @@ src/modes/tutorial_world.cpp
src/modes/world.cpp
src/modes/world_status.cpp
src/modes/world_with_rank.cpp
src/network/connect_message.cpp
src/network/kart_control_message.cpp
src/network/kart_update_message.cpp
src/network/message.cpp
src/network/network_kart.cpp
src/network/client_network_manager.cpp
src/network/event.cpp
src/network/game_setup.cpp
src/network/http_functions.cpp
src/network/network_interface.cpp
src/network/network_manager.cpp
src/network/race_info_message.cpp
src/network/race_result_message.cpp
src/network/race_state.cpp
src/network/network_string.cpp
src/network/network_world.cpp
src/network/protocol.cpp
src/network/protocol_manager.cpp
src/network/protocols/client_lobby_room_protocol.cpp
src/network/protocols/connect_to_peer.cpp
src/network/protocols/connect_to_server.cpp
src/network/protocols/controller_events_protocol.cpp
src/network/protocols/game_events_protocol.cpp
src/network/protocols/get_peer_address.cpp
src/network/protocols/get_public_address.cpp
src/network/protocols/hide_public_address.cpp
src/network/protocols/kart_update_protocol.cpp
src/network/protocols/lobby_room_protocol.cpp
src/network/protocols/ping_protocol.cpp
src/network/protocols/quick_join_protocol.cpp
src/network/protocols/request_connection.cpp
src/network/protocols/server_lobby_room_protocol.cpp
src/network/protocols/show_public_address.cpp
src/network/protocols/start_game_protocol.cpp
src/network/protocols/start_server.cpp
src/network/protocols/stop_server.cpp
src/network/protocols/synchronization_protocol.cpp
src/network/server_network_manager.cpp
src/network/stk_host.cpp
src/network/stk_peer.cpp
src/network/types.cpp
src/online/current_user.cpp
src/online/http_manager.cpp
src/online/messages.cpp
src/online/profile.cpp
src/online/profile_manager.cpp
src/online/request.cpp
src/online/server.cpp
src/online/servers_manager.cpp
src/physics/btKart.cpp
src/physics/btKartRaycast.cpp
src/physics/btUprightConstraint.cpp
@@ -174,21 +213,30 @@ src/replay/replay_play.cpp
src/replay/replay_recorder.cpp
src/states_screens/addons_screen.cpp
src/states_screens/arenas_screen.cpp
src/states_screens/create_server_screen.cpp
src/states_screens/credits.cpp
src/states_screens/cutscene_gui.cpp
src/states_screens/dialogs/add_device_dialog.cpp
src/states_screens/dialogs/addons_loading.cpp
src/states_screens/dialogs/change_password_dialog.cpp
src/states_screens/dialogs/confirm_resolution_dialog.cpp
src/states_screens/dialogs/custom_video_settings.cpp
src/states_screens/dialogs/enter_player_name_dialog.cpp
src/states_screens/dialogs/gp_info_dialog.cpp
src/states_screens/dialogs/login_dialog.cpp
src/states_screens/dialogs/message_dialog.cpp
src/states_screens/dialogs/notification_dialog.cpp
src/states_screens/dialogs/player_info_dialog.cpp
src/states_screens/dialogs/press_a_key_dialog.cpp
src/states_screens/dialogs/race_paused_dialog.cpp
src/states_screens/dialogs/recovery_dialog.cpp
src/states_screens/dialogs/registration_dialog.cpp
src/states_screens/dialogs/select_challenge.cpp
src/states_screens/dialogs/server_info_dialog.cpp
src/states_screens/dialogs/track_info_dialog.cpp
src/states_screens/dialogs/tutorial_message_dialog.cpp
src/states_screens/dialogs/user_info_dialog.cpp
src/states_screens/dialogs/vote_dialog.cpp
src/states_screens/easter_egg_screen.cpp
src/states_screens/feature_unlocked.cpp
src/states_screens/grand_prix_lose.cpp
@@ -199,6 +247,16 @@ src/states_screens/help_screen_3.cpp
src/states_screens/help_screen_4.cpp
src/states_screens/kart_selection.cpp
src/states_screens/main_menu_screen.cpp
src/states_screens/networking_lobby.cpp
src/states_screens/network_kart_selection.cpp
src/states_screens/offline_kart_selection.cpp
src/states_screens/online_profile_achievements.cpp
src/states_screens/online_profile_base.cpp
src/states_screens/online_profile_friends.cpp
src/states_screens/online_profile_overview.cpp
src/states_screens/online_profile_settings.cpp
src/states_screens/online_screen.cpp
src/states_screens/online_user_search.cpp
src/states_screens/options_screen_audio.cpp
src/states_screens/options_screen_input2.cpp
src/states_screens/options_screen_input.cpp
@@ -210,6 +268,7 @@ src/states_screens/race_gui.cpp
src/states_screens/race_gui_overworld.cpp
src/states_screens/race_result_gui.cpp
src/states_screens/race_setup_screen.cpp
src/states_screens/server_selection.cpp
src/states_screens/soccer_setup_screen.cpp
src/states_screens/state_manager.cpp
src/states_screens/story_mode_lobby.cpp
@@ -257,6 +316,10 @@ src/utils/translation.cpp
src/utils/vec3.cpp
)
set(STK_HEADERS
src/achievements/achievement.hpp
src/achievements/achievement_info.hpp
src/achievements/achievements_manager.hpp
src/achievements/achievements_slot.hpp
src/addons/addon.hpp
src/addons/addons_manager.hpp
src/addons/dummy_network_http.hpp
@@ -327,6 +390,7 @@ src/graphics/water.hpp
src/graphics/wind.hpp
src/guiengine/abstract_state_manager.hpp
src/guiengine/abstract_top_level_container.hpp
src/guiengine/dialog_queue.hpp
src/guiengine/engine.hpp
src/guiengine/event_handler.hpp
src/guiengine/layout_manager.hpp
@@ -382,6 +446,7 @@ src/karts/controller/ai_properties.hpp
src/karts/controller/controller.hpp
src/karts/controller/end_controller.hpp
src/karts/controller/kart_control.hpp
src/karts/controller/network_player_controller.hpp
src/karts/controller/player_controller.hpp
src/karts/controller/skidding_ai.hpp
src/karts/explosion_animation.hpp
@@ -412,25 +477,49 @@ src/modes/tutorial_world.hpp
src/modes/world.hpp
src/modes/world_status.hpp
src/modes/world_with_rank.hpp
src/network/character_confirm_message.hpp
src/network/character_info_message.hpp
src/network/character_selected_message.hpp
src/network/connect_message.hpp
src/network/flyable_info.hpp
src/network/item_info.hpp
src/network/kart_control_message.hpp
src/network/kart_update_message.hpp
src/network/message.hpp
src/network/network_kart.hpp
src/network/event.hpp
src/network/client_network_manager.hpp
src/network/game_setup.hpp
src/network/http_functions.hpp
src/network/network_interface.hpp
src/network/network_manager.hpp
src/network/num_players_message.hpp
src/network/race_info_message.hpp
src/network/race_result_ack_message.hpp
src/network/race_result_message.hpp
src/network/race_start_message.hpp
src/network/race_state.hpp
src/network/network_string.hpp
src/network/network_world.hpp
src/network/protocol.hpp
src/network/protocol_manager.hpp
src/network/protocols/client_lobby_room_protocol.hpp
src/network/protocols/connect_to_peer.hpp
src/network/protocols/connect_to_server.hpp
src/network/protocols/controller_events_protocol.hpp
src/network/protocols/game_events_protocol.hpp
src/network/protocols/get_peer_address.hpp
src/network/protocols/get_public_address.hpp
src/network/protocols/hide_public_address.hpp
src/network/protocols/kart_update_protocol.hpp
src/network/protocols/lobby_room_protocol.hpp
src/network/protocols/ping_protocol.hpp
src/network/protocols/quick_join_protocol.hpp
src/network/protocols/request_connection.hpp
src/network/protocols/server_lobby_room_protocol.hpp
src/network/protocols/show_public_address.hpp
src/network/protocols/start_game_protocol.hpp
src/network/protocols/start_server.hpp
src/network/protocols/stop_server.hpp
src/network/protocols/synchronization_protocol.hpp
src/network/remote_kart_info.hpp
src/network/world_loaded_message.hpp
src/network/server_network_manager.hpp
src/network/singleton.hpp
src/network/stk_host.hpp
src/network/stk_peer.hpp
src/network/types.hpp
src/online/current_user.hpp
src/online/http_manager.hpp
src/online/messages.hpp
src/online/profile.hpp
src/online/profile_manager.hpp
src/online/request.hpp
src/online/server.hpp
src/online/servers_manager.hpp
src/physics/btKart.hpp
src/physics/btKartRaycast.hpp
src/physics/btUprightConstraint.hpp
@@ -452,21 +541,30 @@ src/replay/replay_play.hpp
src/replay/replay_recorder.hpp
src/states_screens/addons_screen.hpp
src/states_screens/arenas_screen.hpp
src/states_screens/create_server_screen.hpp
src/states_screens/credits.hpp
src/states_screens/cutscene_gui.hpp
src/states_screens/dialogs/add_device_dialog.hpp
src/states_screens/dialogs/addons_loading.hpp
src/states_screens/dialogs/change_password_dialog.hpp
src/states_screens/dialogs/confirm_resolution_dialog.hpp
src/states_screens/dialogs/custom_video_settings.hpp
src/states_screens/dialogs/enter_player_name_dialog.hpp
src/states_screens/dialogs/gp_info_dialog.hpp
src/states_screens/dialogs/login_dialog.hpp
src/states_screens/dialogs/message_dialog.hpp
src/states_screens/dialogs/notification_dialog.hpp
src/states_screens/dialogs/player_info_dialog.hpp
src/states_screens/dialogs/press_a_key_dialog.hpp
src/states_screens/dialogs/race_paused_dialog.hpp
src/states_screens/dialogs/recovery_dialog.hpp
src/states_screens/dialogs/registration_dialog.hpp
src/states_screens/dialogs/select_challenge.hpp
src/states_screens/dialogs/server_info_dialog.hpp
src/states_screens/dialogs/track_info_dialog.hpp
src/states_screens/dialogs/tutorial_message_dialog.hpp
src/states_screens/dialogs/user_info_dialog.hpp
src/states_screens/dialogs/vote_dialog.hpp
src/states_screens/easter_egg_screen.hpp
src/states_screens/feature_unlocked.hpp
src/states_screens/grand_prix_lose.hpp
@@ -477,6 +575,16 @@ src/states_screens/help_screen_3.hpp
src/states_screens/help_screen_4.hpp
src/states_screens/kart_selection.hpp
src/states_screens/main_menu_screen.hpp
src/states_screens/networking_lobby.hpp
src/states_screens/network_kart_selection.hpp
src/states_screens/offline_kart_selection.hpp
src/states_screens/online_profile_achievements.hpp
src/states_screens/online_profile_base.hpp
src/states_screens/online_profile_friends.hpp
src/states_screens/online_profile_overview.hpp
src/states_screens/online_profile_settings.hpp
src/states_screens/online_screen.hpp
src/states_screens/online_user_search.hpp
src/states_screens/options_screen_audio.hpp
src/states_screens/options_screen_input2.hpp
src/states_screens/options_screen_input.hpp
@@ -488,6 +596,7 @@ src/states_screens/race_gui.hpp
src/states_screens/race_gui_overworld.hpp
src/states_screens/race_result_gui.hpp
src/states_screens/race_setup_screen.hpp
src/states_screens/server_selection.hpp
src/states_screens/soccer_setup_screen.hpp
src/states_screens/state_manager.hpp
src/states_screens/story_mode_lobby.hpp
@@ -539,6 +648,7 @@ src/utils/string_utils.hpp
src/utils/synchronised.hpp
src/utils/time.hpp
src/utils/translation.hpp
src/utils/types.hpp
src/utils/vec3.hpp
src/utils/vs.hpp
)

View File

@@ -0,0 +1,209 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 Glenn De Jonghe
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "achievements/achievement.hpp"
#include "achievements/achievement_info.hpp"
#include "guiengine/dialog_queue.hpp"
#include "states_screens/dialogs/notification_dialog.hpp"
#include "io/xml_writer.hpp"
#include "utils/log.hpp"
#include "utils/translation.hpp"
#include <sstream>
#include <stdlib.h>
#include <assert.h>
// ============================================================================
Achievement::Achievement(const AchievementInfo * info)
:m_achievement_info(info)
{
m_id = info->getID();
m_achieved = false;
}
// ============================================================================
Achievement::~Achievement()
{
}
// ============================================================================
void Achievement::onRaceEnd()
{
if(m_achievement_info->needsResetAfterRace())
this->reset();
}
// ============================================================================
void Achievement::check()
{
if(m_achieved)
return;
if(m_achievement_info->checkCompletion(this))
{
//show achievement
GUIEngine::DialogQueue::get()->pushDialog(
new NotificationDialog(NotificationDialog::T_Achievements,
irr::core::stringw(_("Completed achievement")) + irr::core::stringw(" \"") + m_achievement_info->getTitle() + irr::core::stringw("\".")
));
//send to server
Online::CurrentUser::get()->onAchieving(m_id);
m_achieved = true;
}
}
// ============================================================================
SingleAchievement::SingleAchievement(const AchievementInfo * info)
: Achievement(info)
{
m_progress = 0;
m_achieved = false;
}
// ============================================================================
void SingleAchievement::load(XMLNode * input)
{
std::string achieved("");
input->get("achieved", &achieved);
if(achieved == "true")
{
m_achieved = true;
return;
}
input->get("value", &m_progress);
}
// ============================================================================
void SingleAchievement::save(std::ofstream & out)
{
out << " <achievement id=\"" << m_id << "\" "
<< "achieved=\"" << StringUtils::boolstr(m_achieved) << "\"";
if(!m_achieved)
{
out << " value=\"" << StringUtils::toString(m_progress) << "\"";
}
out << "/>\n";
} // save
// ============================================================================
void SingleAchievement::reset()
{
m_progress = 0;
} // reset
// ============================================================================
void SingleAchievement::increase(int increase)
{
m_progress += increase;
check();
}
// ============================================================================
irr::core::stringw SingleAchievement::getProgressAsString()
{
return StringUtils::toWString(m_progress) + "/" + StringUtils::toWString(((SingleAchievementInfo *) m_achievement_info)->getGoalValue());
}
// ============================================================================
MapAchievement::MapAchievement(const AchievementInfo * info)
: Achievement(info)
{
}
// ============================================================================
void MapAchievement::load(XMLNode * input)
{
std::string achieved("");
input->get("achieved", &achieved);
if(achieved == "true")
{
m_achieved = true;
return;
}
std::vector<XMLNode*> xml_entries;
input->getNodes("entry", xml_entries);
for (unsigned int n=0; n < xml_entries.size(); n++)
{
std::string key("");
xml_entries[n]->get("key", &key);
int value(0);
xml_entries[n]->get("value", &value);
m_progress_map[key] = value;
}
}
// ============================================================================
void MapAchievement::save(std::ofstream & out)
{
out << " <achievement id=\"" << m_id << "\" achieved=\"" << StringUtils::boolstr(m_achieved) << "\">\n";
if(!m_achieved)
{
std::map<std::string, int>::iterator iter;
for ( iter = m_progress_map.begin(); iter != m_progress_map.end(); ++iter ) {
out << " <entry key=\"" << iter->first.c_str() << "\" value=\"" << StringUtils::toString(iter->second) << "\"/>\n";
}
}
out << " </achievement>\n";
} // save
// ============================================================================
int MapAchievement::getValue(const std::string & key)
{
if ( m_progress_map.find(key) != m_progress_map.end())
return m_progress_map[key];
return 0;
}
// ============================================================================
void MapAchievement::reset()
{
std::map<std::string, int>::iterator iter;
for ( iter = m_progress_map.begin(); iter != m_progress_map.end(); ++iter ) {
iter->second = 0;
}
} // reset
// ============================================================================
void MapAchievement::increase(const std::string & key, int increase)
{
if ( m_progress_map.find(key) != m_progress_map.end())
{
m_progress_map[key] += increase;
check();
}
}
// ============================================================================
irr::core::stringw MapAchievement::getProgressAsString()
{
int progress(0);
int goal(0);
const std::map<std::string, int> goal_values = ((MapAchievementInfo *) m_achievement_info)->getGoalValues();
std::map<std::string, int>::const_iterator iter;
for ( iter = goal_values.begin(); iter != goal_values.end(); ++iter ) {
goal += iter->second;
progress += m_progress_map[iter->first];
}
return StringUtils::toWString(progress) + "/" + StringUtils::toWString(goal);
}

View File

@@ -0,0 +1,101 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 Glenn De Jonghe
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_ACHIEVEMENT_HPP
#define HEADER_ACHIEVEMENT_HPP
#include "utils/types.hpp"
#include <irrString.h>
#include <string>
#include "io/xml_node.hpp"
// ============================================================================
/**
* \brief
* \ingroup
*/
class AchievementInfo;
class Achievement
{
protected:
uint32_t m_id;
bool m_achieved;
const AchievementInfo * m_achievement_info;
void check ();
public:
Achievement (const AchievementInfo * info);
virtual ~Achievement ();
uint32_t getID () const { return m_id; }
const AchievementInfo * getInfo () const { return m_achievement_info;}
virtual void load (XMLNode * input) = 0;
virtual void save (std::ofstream & out) = 0;
virtual void reset () = 0;
void onRaceEnd ();
void setAchieved () {m_achieved = true; };
virtual irr::core::stringw getProgressAsString () = 0;
enum AchievementType
{
AT_SINGLE,
AT_MAP
};
}; // class Achievement
class SingleAchievement : public Achievement
{
protected:
int m_progress;
public:
SingleAchievement (const AchievementInfo * info);
virtual ~SingleAchievement () {};
void load (XMLNode * input);
int getValue () const { return m_progress; }
void save (std::ofstream & out);
void increase (int increase = 1);
void reset ();
virtual irr::core::stringw getProgressAsString ();
}; // class SingleAchievement
class MapAchievement : public Achievement
{
protected:
std::map<std::string, int> m_progress_map;
public:
MapAchievement (const AchievementInfo * info);
virtual ~MapAchievement () {};
void load (XMLNode * input);
int getValue (const std::string & key);
void increase (const std::string & key, int increase = 1);
void save (std::ofstream & out);
void reset ();
virtual irr::core::stringw getProgressAsString ();
}; // class MapAchievement
#endif
/*EOF*/

View File

@@ -0,0 +1,87 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 Glenn De Jonghe
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "achievements/achievement_info.hpp"
#include "utils/log.hpp"
#include "utils/translation.hpp"
#include "io/xml_writer.hpp"
#include <sstream>
#include <stdlib.h>
#include <assert.h>
// ============================================================================
AchievementInfo::AchievementInfo(const XMLNode * input)
{
input->get("id", &m_id);
input->get("title", &m_title);
input->get("description", &m_description);
std::string reset_after_race("");
input->get("reset_after_race", &reset_after_race);
m_reset_after_race = reset_after_race == "true";
}
// ============================================================================
SingleAchievementInfo::SingleAchievementInfo(const XMLNode * input)
: AchievementInfo(input)
{
input->get("goal", &m_goal_value);
}
// ============================================================================
bool SingleAchievementInfo::checkCompletion(Achievement * achievement) const
{
SingleAchievement * single_achievement = (SingleAchievement *) achievement;
if(single_achievement->getValue() >= m_goal_value)
return true;
return false;
}
// ============================================================================
MapAchievementInfo::MapAchievementInfo(const XMLNode * input)
: AchievementInfo(input)
{
std::vector<XMLNode*> xml_entries;
input->getNodes("entry", xml_entries);
for (unsigned int n=0; n < xml_entries.size(); n++)
{
std::string key("");
xml_entries[n]->get("key", &key);
int goal(0);
xml_entries[n]->get("goal", &goal);
m_goal_values[key] = goal;
}
if(m_goal_values.size() != xml_entries.size())
Log::error("MapAchievementInfo","Duplicate keys for the entries of a MapAchievement found.");
}
// ============================================================================
bool MapAchievementInfo::checkCompletion(Achievement * achievement) const
{
MapAchievement * map_achievement = (MapAchievement *) achievement;
std::map<std::string, int>::const_iterator iter;
for ( iter = m_goal_values.begin(); iter != m_goal_values.end(); iter++ ) {
if(map_achievement->getValue(iter->first) < iter->second)
return false;
}
return true;
}

View File

@@ -0,0 +1,87 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 Glenn De Jonghe
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_ACHIEVEMENT_INFO_HPP
#define HEADER_ACHIEVEMENT_INFO_HPP
#include "utils/types.hpp"
#include <irrString.h>
#include <string>
#include "io/xml_node.hpp"
#include "achievements/achievement.hpp"
// ============================================================================
class Achievement;
/**
* \brief
* \ingroup
*/
class AchievementInfo
{
protected:
uint32_t m_id;
irr::core::stringw m_title;
irr::core::stringw m_description;
bool m_reset_after_race;
public:
AchievementInfo (const XMLNode * input);
virtual ~AchievementInfo () {};
uint32_t getID () const { return m_id; }
irr::core::stringw getDescription () const { return m_description; }
irr::core::stringw getTitle () const { return m_title; }
virtual Achievement::AchievementType getType () const = 0;
virtual bool checkCompletion (Achievement * achievement) const = 0;
bool needsResetAfterRace() const {return m_reset_after_race; }
}; // class AchievementInfo
class SingleAchievementInfo : public AchievementInfo
{
protected:
int m_goal_value;
public:
SingleAchievementInfo (const XMLNode * input);
virtual ~SingleAchievementInfo () {};
int getGoalValue () const { return m_goal_value; }
virtual bool checkCompletion (Achievement * achievement) const;
virtual Achievement::AchievementType getType() const { return Achievement::AT_SINGLE; };
}; // class SingleAchievementInfo
class MapAchievementInfo : public AchievementInfo
{
protected:
std::map<std::string, int> m_goal_values;
public:
MapAchievementInfo (const XMLNode * input);
virtual ~MapAchievementInfo () {};
int getGoalValue (const std::string & key) { return m_goal_values[key];}
const std::map<std::string, int> & getGoalValues() const {return m_goal_values;}
virtual bool checkCompletion (Achievement * achievement) const;
virtual Achievement::AchievementType getType() const { return Achievement::AT_MAP; };
}; // class MapAchievementInfo
#endif
/*EOF*/

View File

@@ -0,0 +1,247 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 Glenn De Jonghe
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "achievements/achievements_manager.hpp"
#include "utils/log.hpp"
#include "utils/translation.hpp"
#include "io/file_manager.hpp"
#include "io/xml_writer.hpp"
#include "config/player.hpp"
#include "config/user_config.hpp"
#include "online/current_user.hpp"
#include "challenges/unlock_manager.hpp"
#include <sstream>
#include <stdlib.h>
#include <assert.h>
static AchievementsManager* achievements_manager_singleton(NULL);
AchievementsManager* AchievementsManager::get()
{
if (achievements_manager_singleton == NULL)
achievements_manager_singleton = new AchievementsManager();
return achievements_manager_singleton;
}
void AchievementsManager::deallocate()
{
delete achievements_manager_singleton;
achievements_manager_singleton = NULL;
} // deallocate
// ============================================================================
AchievementsManager::AchievementsManager()
{
parseDataFile();
}
// ============================================================================
void AchievementsManager::init()
{
parseConfigFile();
}
// ============================================================================
AchievementsManager::~AchievementsManager()
{
save();
m_slots.clearAndDeleteAll();
std::map<uint32_t, AchievementInfo *>::iterator it;
for ( it = m_achievements_info.begin(); it != m_achievements_info.end(); ++it ) {
delete it->second;
}
m_achievements_info.clear();
}
// ============================================================================
void AchievementsManager::parseDataFile()
{
const std::string file_name = file_manager->getDataFile("achievements.xml");
const XMLNode *root = file_manager->createXMLTree(file_name);
unsigned int num_nodes = root->getNumNodes();
for(unsigned int i = 0; i < num_nodes; i++)
{
const XMLNode *node = root->getNode(i);
std::string type("");
node->get("type", &type);
AchievementInfo * achievement_info;
if(type == "single")
{
achievement_info = new SingleAchievementInfo(node);
}
else if(type == "map")
{
achievement_info = new MapAchievementInfo(node);
}
else
{
Log::error("AchievementsManager::parseAchievements","Non-existent achievement type. Skipping - definitely results in unwanted behaviour.");
continue;
}
m_achievements_info[achievement_info->getID()] = achievement_info;
}
if(num_nodes != m_achievements_info.size())
Log::error("AchievementsManager::parseAchievements","Multiple achievements with the same id!");
}
// ============================================================================
void AchievementsManager::parseConfigFile()
{
const std::string filename=file_manager->getConfigFile("achievements.xml");
XMLNode* root = file_manager->createXMLTree(filename);
if(!root || root->getName() != "achievements")
{
Log::info("AchievementsManager", "Achievements file '%s' will be created.",filename.c_str());
createSlotsIfNeeded();
if (root) delete root;
return;
}
std::vector<XMLNode*> xml_slots;
root->getNodes("slot", xml_slots);
for (unsigned int n=0; n < xml_slots.size(); n++)
{
AchievementsSlot * slot = new AchievementsSlot(xml_slots[n]);
if(!slot->isValid())
{
Log::warn("AchievementsManager", "Found game slot with faulty or missing information. Discarding it.");
delete slot;
continue;
}
m_slots.push_back(slot);
}
delete root;
} // load
AchievementsSlot * AchievementsManager::createNewSlot(std::string id, bool online)
{
AchievementsSlot* slot = new AchievementsSlot(id, online);
m_slots.push_back(slot);
return slot;
}
//-----------------------------------------------------------------------------
/** Creates a slot for players that don't have one yet
* \return true if any were created
*/
void AchievementsManager::createSlotsIfNeeded()
{
bool something_changed = false;
// make sure all players have at least one game slot associated
PtrVector<PlayerProfile>& players = UserConfigParams::m_all_players;
for (int n=0; n<players.size(); n++)
{
if (getSlot(players[n].getUniqueID(), false) == NULL )
{
createNewSlot(players[n].getUniqueID(), false);
something_changed = true;
}
}
if(something_changed){
save();
}
} // UnlockManager::createSlotsIfNeeded
// ============================================================================
void AchievementsManager::save()
{
std::string filename = file_manager->getConfigFile("achievements.xml");
std::ofstream achievements_file(filename.c_str(), std::ios::out);
if (!achievements_file.is_open())
{
Log::warn("AchievementsManager::save",
"Failed to open '%s' for writing, achievements won't be saved\n",
filename.c_str());
return;
}
achievements_file << "<?xml version=\"1.0\"?>\n";
achievements_file << "<achievements>\n";
for (int i = 0; i < m_slots.size(); i++)
{
m_slots[i].save(achievements_file);
}
achievements_file << "</achievements>\n\n";
achievements_file.close();
}
// ============================================================================
void AchievementsManager::onRaceEnd()
{
//reset all values that need to be reset
m_active_slot->onRaceEnd();
}
// ============================================================================
AchievementsSlot * AchievementsManager::getSlot(const std::string & id, bool online)
{
for(int i = 0; i < m_slots.size(); i++)
{
if(m_slots[i].isOnline() == online && m_slots[i].getID() == id)
{
return m_slots.get(i);
}
}
return NULL;
}
// ============================================================================
void AchievementsManager::updateCurrentPlayer()
{
if(Online::CurrentUser::get()->isRegisteredUser())
{
m_active_slot = getSlot(StringUtils::toString(Online::CurrentUser::get()->getID()), true);
if(m_active_slot == NULL)
{
m_active_slot = createNewSlot(StringUtils::toString(Online::CurrentUser::get()->getID()), true);
save();
}
}
else
{
m_active_slot = getSlot(unlock_manager->getCurrentPlayer()->getUniqueID(), false);
if(m_active_slot == NULL)
{
m_active_slot = createNewSlot(unlock_manager->getCurrentPlayer()->getUniqueID(), false);
save();
}
}
}
// ============================================================================
AchievementInfo * AchievementsManager::getAchievementInfo(uint32_t id)
{
if ( m_achievements_info.find(id) != m_achievements_info.end())
return m_achievements_info[id];
return NULL;
}

View File

@@ -0,0 +1,70 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 Glenn De Jonghe
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_ACHIEVEMENTS_MANAGER_HPP
#define HEADER_ACHIEVEMENTS_MANAGER_HPP
#include "utils/types.hpp"
#include "utils/ptr_vector.hpp"
#include "achievements/achievement_info.hpp"
#include "achievements/achievements_slot.hpp"
#include <irrString.h>
#include <string>
#include <vector>
#include <map>
// ============================================================================
/**
* \brief Class that takes care of online profiles
* \ingroup online
*/
class AchievementsManager
{
private :
AchievementsSlot * m_active_slot;
PtrVector<AchievementsSlot> m_slots;
std::map<uint32_t, AchievementInfo *> m_achievements_info;
AchievementsManager ();
~AchievementsManager ();
AchievementsSlot * createNewSlot(std::string id, bool online);
void parseDataFile();
void parseConfigFile();
public:
/**Singleton */
static AchievementsManager * get();
static void deallocate();
void init();
void save();
void onRaceEnd();
void updateCurrentPlayer();
AchievementsSlot * getActive() const { return m_active_slot; }
AchievementsSlot * getSlot(const std::string & id, bool online);
void createSlotsIfNeeded();
AchievementInfo * getAchievementInfo(uint32_t id);
const std::map<uint32_t, AchievementInfo *> & getAllInfo() { return m_achievements_info;}
}; // class AchievementsManager
#endif
/*EOF*/

View File

@@ -0,0 +1,153 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 Glenn De Jonghe
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "achievements/achievements_slot.hpp"
#include "achievements/achievement_info.hpp"
#include "achievements/achievements_manager.hpp"
#include "utils/log.hpp"
#include "utils/ptr_vector.hpp"
#include "utils/translation.hpp"
#include "io/xml_writer.hpp"
#include "online/current_user.hpp"
#include <sstream>
#include <stdlib.h>
#include <assert.h>
// ============================================================================
AchievementsSlot::AchievementsSlot(const XMLNode * input)
{
int fetched_user_id = input->get("user_id", &m_id);
std::string online;
int fetched_online = input->get("online", &online);
if(!fetched_user_id || !fetched_online || !(online == "true" || online == "false"))
{
m_valid = false;
}
m_valid = true;
m_online = online == "true";
createFreshSlot();
std::vector<XMLNode*> xml_achievements;
input->getNodes("achievement", xml_achievements);
for( unsigned int i=0; i<xml_achievements.size(); i++)
{
uint32_t achievement_id(0);
xml_achievements[i]->get("id", &achievement_id);
Achievement * achievement = getAchievement(achievement_id);
if(achievement == NULL)
{
Log::warn("AchievementsSlot", "Found saved achievement data for a non-existent achievement. Discarding.");
continue;
}
achievement->load(xml_achievements[i]);
}
}
// ============================================================================
AchievementsSlot::AchievementsSlot(std::string id, bool online)
{
m_valid = true;
m_online = online;
m_id = id;
createFreshSlot();
}
// ============================================================================
AchievementsSlot::~AchievementsSlot()
{
deleteAchievements();
}
// ============================================================================
void AchievementsSlot::deleteAchievements()
{
std::map<uint32_t, Achievement *>::iterator it;
for ( it = m_achievements.begin(); it != m_achievements.end(); ++it ) {
delete it->second;
}
m_achievements.clear();
}
// ============================================================================
void AchievementsSlot::createFreshSlot()
{
deleteAchievements();
const std::map<uint32_t, AchievementInfo *> all_info = AchievementsManager::get()->getAllInfo();
std::map<uint32_t, AchievementInfo *>::const_iterator it;
for ( it = all_info.begin(); it != all_info.end(); ++it ) {
Achievement::AchievementType achievement_type = it->second->getType();
Achievement * achievement;
if(achievement_type == Achievement::AT_SINGLE)
{
achievement = new SingleAchievement(it->second);
}
else if(achievement_type == Achievement::AT_MAP)
{
achievement = new MapAchievement(it->second);
}
m_achievements[achievement->getID()] = achievement;
}
}
// ============================================================================
void AchievementsSlot::save(std::ofstream & out)
{
out << " <slot user_id=\"" << m_id.c_str()
<< "\" online=\"" << StringUtils::boolstr(m_online)
<< "\"> \n";
std::map<uint32_t, Achievement*>::const_iterator i;
for(i = m_achievements.begin(); i != m_achievements.end(); i++)
{
if (i->second != NULL)
i->second->save(out);
}
out << " </slot>\n";
}
// ============================================================================
Achievement * AchievementsSlot::getAchievement(uint32_t id)
{
if ( m_achievements.find(id) != m_achievements.end())
return m_achievements[id];
return NULL;
}
// ============================================================================
void AchievementsSlot::sync(const std::vector<uint32_t> & achieved_ids)
{
for(unsigned int i =0; i < achieved_ids.size(); ++i)
{
Achievement * achievement = getAchievement(achieved_ids[i]);
if(achievement != NULL)
achievement->setAchieved();
}
}
// ============================================================================
void AchievementsSlot::onRaceEnd()
{
//reset all values that need to be reset
std::map<uint32_t, Achievement *>::iterator iter;
for ( iter = m_achievements.begin(); iter != m_achievements.end(); ++iter ) {
iter->second->onRaceEnd();
}
}

View File

@@ -0,0 +1,64 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 Glenn De Jonghe
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_ACHIEVEMENTS_SLOT_HPP
#define HEADER_ACHIEVEMENTS_SLOT_HPP
#include "utils/types.hpp"
#include "achievements/achievement.hpp"
#include "online/http_manager.hpp"
#include <irrString.h>
#include <string>
#include "io/xml_node.hpp"
class AchievementsSlot
{
private:
std::map<uint32_t, Achievement *> m_achievements;
bool m_online;
bool m_valid;
std::string m_id;
void createFreshSlot();
void deleteAchievements();
class SyncAchievementsRequest : public Online::XMLRequest {
virtual void callback ();
public:
SyncAchievementsRequest() : Online::XMLRequest(true) {}
};
public :
AchievementsSlot(const XMLNode * input);
AchievementsSlot(std::string id, bool online);
~AchievementsSlot();
bool isValid() const { return m_valid;}
void save(std::ofstream & out);
bool isOnline() const {return m_online;}
void sync(const std::vector<uint32_t> & achieved_ids);
void onRaceEnd();
const std::string & getID() const {return m_id;}
const std::map<uint32_t, Achievement *> & getAllAchievements() {return m_achievements;}
Achievement * getAchievement(uint32_t id);
};
#endif
/*EOF*/

View File

@@ -115,7 +115,7 @@ private:
/** Compressed size of the addon package. */
int m_size;
/** Rating for thsi addon package. */
float m_rating;
mutable float m_rating;
/** Minimum version addon is included with. */
std::string m_min_include_ver;
/** Maximum version addon is included with. */
@@ -151,6 +151,9 @@ public:
/** Returns the rating of an addon. */
const float getRating() const {return m_rating; }
// ------------------------------------------------------------------------
/** Sets the rating of an addon. */
void setRating(const float rating) const {m_rating = rating; }
// ------------------------------------------------------------------------
/** Returns the type of the addon. */
const std::string& getType() const { return m_type; }
// ------------------------------------------------------------------------

View File

@@ -27,7 +27,7 @@
#include <vector>
#ifdef WIN32
# include <winsock2.h>
# include <WinSock2.h>
#endif
#include <curl/curl.h>

View File

@@ -307,7 +307,7 @@ SFXBase* SFXManager::createSoundSource(SFXBuffer* buffer,
// race_manager->getNumLocalPlayers(), buffer->isPositional());
#if HAVE_OGGVORBIS
assert( alIsBuffer(buffer->getBufferID()) );
//assert( alIsBuffer(buffer->getBufferID()) ); crashes on server
SFXBase* sfx = new SFXOpenAL(buffer, positional, buffer->getGain(), owns_buffer);
#else
SFXBase* sfx = new DummySFX(buffer, positional, buffer->getGain(), owns_buffer);

View File

@@ -90,17 +90,11 @@ void Challenge::setSolved(RaceManager::Difficulty d)
//-----------------------------------------------------------------------------
const char* boolstr(bool b)
{
return (b ? "true" : "false");
}
void Challenge::save(std::ofstream& writer)
{
writer << " <" << m_data->getId().c_str() << ">\n"
<< " <easy solved=\"" << boolstr(isSolved(RaceManager::DIFFICULTY_EASY)) << "\"/>\n"
<< " <medium solved=\"" << boolstr(isSolved(RaceManager::DIFFICULTY_MEDIUM)) << "\"/>\n"
<< " <hard solved=\"" << boolstr(isSolved(RaceManager::DIFFICULTY_HARD)) << "\"/>\n"
<< " <easy solved=\"" << StringUtils::boolstr(isSolved(RaceManager::DIFFICULTY_EASY)) << "\"/>\n"
<< " <medium solved=\"" << StringUtils::boolstr(isSolved(RaceManager::DIFFICULTY_MEDIUM)) << "\"/>\n"
<< " <hard solved=\"" << StringUtils::boolstr(isSolved(RaceManager::DIFFICULTY_HARD)) << "\"/>\n"
<< " </" << m_data->getId().c_str() << ">\n";
} // save

View File

@@ -24,6 +24,7 @@
#include <stdio.h>
#include <iostream>
#include "achievements/achievements_manager.hpp"
#include "audio/sfx_base.hpp"
#include "audio/sfx_manager.hpp"
#include "config/player.hpp"
@@ -204,7 +205,7 @@ const ChallengeData* UnlockManager::getChallenge(const std::string& id)
*/
void UnlockManager::load()
{
const std::string filename=file_manager->getChallengeFile("challenges.xml");
const std::string filename=file_manager->getConfigFile("challenges.xml");
XMLNode* root = file_manager->createXMLTree(filename);
if(!root || root->getName() != "challenges")
{
@@ -263,7 +264,7 @@ void UnlockManager::load()
void UnlockManager::save()
{
std::string filename = file_manager->getChallengeFile("challenges.xml");
std::string filename = file_manager->getConfigFile("challenges.xml");
std::ofstream challenge_file(filename.c_str(), std::ios::out);
@@ -421,6 +422,15 @@ void UnlockManager::updateActiveChallengeList()
getCurrentSlot()->computeActive();
}
//-----------------------------------------------------------------------------
void UnlockManager::setCurrentSlot(std::string slotid)
{
m_current_game_slot = slotid;
AchievementsManager::get()->updateCurrentPlayer();
}
//-----------------------------------------------------------------------------
void UnlockManager::findWhatWasUnlocked(int points_before, int points_now,

View File

@@ -82,8 +82,7 @@ public:
}
/** \param slotid name of the player */
void setCurrentSlot(std::string slotid) { m_current_game_slot = slotid; }
void setCurrentSlot(std::string slotid);
void findWhatWasUnlocked(int pointsBefore, int pointsNow,
std::vector<std::string>& tracks,
std::vector<std::string>& gps);

View File

@@ -486,13 +486,15 @@ namespace UserConfigParams
// not saved to file
// ---- Networking
PARAM_PREFIX StringUserConfigParam m_server_address
PARAM_DEFAULT( StringUserConfigParam("localhost", "server_adress",
"Information about last server used") );
PARAM_PREFIX IntUserConfigParam m_server_port
PARAM_DEFAULT( IntUserConfigParam(2305, "server_port",
"Information about last server used") );
PARAM_DEFAULT( IntUserConfigParam(7321, "server_port",
"Information about the port to listen on.") );
PARAM_PREFIX IntUserConfigParam m_server_max_players
PARAM_DEFAULT( IntUserConfigParam(16, "server_max_players",
"Maximum number of players on the server.") );
// ---- Graphic Quality
PARAM_PREFIX GroupUserConfigParam m_graphics_quality
PARAM_DEFAULT( GroupUserConfigParam("GFX",
@@ -614,9 +616,48 @@ namespace UserConfigParams
PARAM_DEFAULT( WStringUserConfigParam(L"", "default_player",
"Which player to use by default (if empty, will prompt)") );
// ---- Internet related
PARAM_PREFIX IntUserConfigParam m_internet_status
PARAM_DEFAULT( IntUserConfigParam(0, "enable_internet",
"Status of internet: 0 user "
"wasn't asked, 1: allowed, 2: "
"not allowed") );
// ---- Online gameplay related
PARAM_PREFIX GroupUserConfigParam m_online_group
PARAM_DEFAULT( GroupUserConfigParam("OnlinePlay",
"Everything related to online play.") );
PARAM_PREFIX StringUserConfigParam m_server_multiplayer
PARAM_DEFAULT( StringUserConfigParam( "https://api.stkaddons.net/",
"server_multiplayer",
&m_online_group,
"The server used for online multiplayer."));
PARAM_PREFIX BoolUserConfigParam m_saved_session
PARAM_DEFAULT( BoolUserConfigParam( false,
"saved_session",
&m_online_group,
"Is there a saved session?") );
PARAM_PREFIX IntUserConfigParam m_saved_user
PARAM_DEFAULT( IntUserConfigParam( 0,
"saved_user",
&m_online_group,
"User ID of the saved session.") );
PARAM_PREFIX StringUserConfigParam m_saved_token
PARAM_DEFAULT( StringUserConfigParam( "",
"saved_token",
&m_online_group,
"Token of the saved session.") );
// ---- Addon server related entries
PARAM_PREFIX GroupUserConfigParam m_addon_group
PARAM_DEFAULT( GroupUserConfigParam("AddonAndNews",
PARAM_DEFAULT( GroupUserConfigParam("AddonAndNews",
"Addon and news related settings") );
PARAM_PREFIX StringUserConfigParam m_server_addons
@@ -647,13 +688,6 @@ namespace UserConfigParams
"Don't show important message "
"with this or a lower id again") );
PARAM_PREFIX IntUserConfigParam m_internet_status
PARAM_DEFAULT( IntUserConfigParam(0, "enable_internet",
&m_addon_group,
"Status of internet: 0 user "
"wasn't asked, 1: allowed, 2: "
"not allowed") );
PARAM_PREFIX TimeUserConfigParam m_addons_last_updated
PARAM_DEFAULT( TimeUserConfigParam(0, "addon_last_updated",
&m_addon_group,

View File

@@ -0,0 +1,82 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 Glenn De Jonghe
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "guiengine/dialog_queue.hpp"
#include "assert.h"
using namespace GUIEngine;
namespace GUIEngine
{
static DialogQueue* dialog_queue_singleton(NULL);
DialogQueue* DialogQueue::get()
{
if (dialog_queue_singleton == NULL)
dialog_queue_singleton = new DialogQueue();
return dialog_queue_singleton;
}
void DialogQueue::deallocate()
{
delete dialog_queue_singleton;
dialog_queue_singleton = NULL;
} // deallocate
// ----------------------------------------------------------------------------
DialogQueue::DialogQueue()
{
m_closer = NULL;
}
// ----------------------------------------------------------------------------
void DialogQueue::pushDialog(ModalDialog * dialog, bool closes_any_dialog)
{
assert(!dialog->isInited());
if(closes_any_dialog)
{
delete m_closer;
m_closer = dialog;
}
else
m_queue.push(dialog);
}
// ----------------------------------------------------------------------------
void DialogQueue::update()
{
if(m_closer != NULL)
{
ModalDialog::dismiss();
m_closer->load();
m_closer = NULL;
}
else if(!m_queue.empty())
{
ModalDialog * entry = m_queue.front();
if(!ModalDialog::isADialogActive())
{
entry->load();
m_queue.pop();
}
}
}
}

View File

@@ -1,6 +1,5 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2008-2013 Joerg Henrichs
// Copyright (C) 2013 Glenn De Jonghe
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -16,25 +15,33 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_RACE_START_MESSAGE_HPP
#define HEADER_RACE_START_MESSAGE_HPP
#ifndef HEADER_DIALOG_QUEUE_HPP
#define HEADER_DIALOG_QUEUE_HPP
#include "network/message.hpp"
#include "network/remote_kart_info.hpp"
#include "race/race_manager.hpp"
#include <queue>
#include "guiengine/modaldialog.hpp"
class RaceStartMessage : public Message
/**
* \ingroup guiengine
*/
namespace GUIEngine
{
private:
// For now this is an empty message
public:
RaceStartMessage() : Message(Message::MT_RACE_START)
{
allocate(0);
} // RaceStartMessage
RaceStartMessage(ENetPacket* pkt):Message(pkt, MT_RACE_START)
class DialogQueue
{
}
}; // RaceStartMessage
private :
std::queue<ModalDialog *> m_queue;
ModalDialog * m_closer;
DialogQueue();
public :
/**Singleton */
static DialogQueue * get();
static void deallocate();
void pushDialog(ModalDialog * dialog, bool closes_any_dialog = false);
void update();
};
}
#endif

View File

@@ -485,7 +485,7 @@ namespace GUIEngine
Used on divs, indicate by how many pixels to pad contents
\n
<HR>
\section code Using the engine in code
@@ -657,6 +657,7 @@ namespace GUIEngine
#include "guiengine/screen.hpp"
#include "guiengine/skin.hpp"
#include "guiengine/widget.hpp"
#include "guiengine/dialog_queue.hpp"
#include "modes/demo_world.hpp"
#include "modes/world.hpp"
#include "states_screens/race_gui_base.hpp"
@@ -835,6 +836,7 @@ namespace GUIEngine
{
widget->update(dt);
}
DialogQueue::get()->update();
}
// Hack : on the first frame, irrlicht processes all events that have been queued
@@ -915,6 +917,25 @@ namespace GUIEngine
g_loaded_screens.push_back(cutscene);
} // addScreenToList
// ------------------------------------------------------------------------
void removeScreen(const char* name)
{
const int screen_amount = g_loaded_screens.size();
for(int n=0; n<screen_amount; n++)
{
if (g_loaded_screens[n].getName() == name)
{
g_current_screen = g_loaded_screens.get(n);
g_current_screen->unload();
delete g_current_screen;
g_current_screen = NULL;
g_loaded_screens.remove(n);
break;
}
}
}
// ------------------------------------------------------------------------
void reshowCurrentScreen()
{

View File

@@ -195,6 +195,8 @@ namespace GUIEngine
/** \brief Add a screen to the list of screens known by the gui engine */
void addScreenToList(Screen* screen);
/** \brief Remove a screen from the list of screens known by the gui engine */
void removeScreen(const char* name);
/** \brief Low-level mean to change current screen.
* \note Do not use directly. Use a state manager instead to get higher-level functionnality.

View File

@@ -689,13 +689,14 @@ EventPropagation EventHandler::onGUIEvent(const SEvent& event)
{
Widget* w = GUIEngine::getWidget(id);
if (w == NULL) break;
if (w->m_deactivated)
{
GUIEngine::getCurrentScreen()->onDisabledItemClicked(w->m_properties[PROP_ID].c_str());
return EVENT_BLOCK;
}
w->onClick();
// These events are only triggered by mouse (or so I hope)
// The player that owns the mouser receives "game master" priviledges
return onWidgetActivated(w, PLAYER_ID_GAME_MASTER);
@@ -741,7 +742,7 @@ EventPropagation EventHandler::onGUIEvent(const SEvent& event)
if (playerID == -1) break;
if (input_manager->masterPlayerOnly() && playerID != PLAYER_ID_GAME_MASTER) break;
if (ribbon->mouseHovered(w, playerID) == EVENT_LET) sendEventToUser(ribbon, ribbon->m_properties[PROP_ID], playerID);
ribbon->mouseHovered(w, playerID);
if (ribbon->m_event_handler != NULL) ribbon->m_event_handler->mouseHovered(w, playerID);
ribbon->setFocusForPlayer(playerID);
}

View File

@@ -47,17 +47,19 @@ using namespace GUIEngine;
// ----------------------------------------------------------------------------
ModalDialog::ModalDialog(const float percentWidth, const float percentHeight,
ModalDialogLocation location)
ModalDialog::ModalDialog(const float percentWidth, const float percentHeight, ModalDialogLocation location)
{
m_dialog_location = location;
doInit(percentWidth, percentHeight);
m_init = false;
m_percent_width = percentWidth;
m_percent_height = percentHeight;
}
// ----------------------------------------------------------------------------
void ModalDialog::loadFromFile(const char* xmlFile)
{
doInit();
IXMLReader* xml = file_manager->createXMLReader( (file_manager->getGUIDir() + xmlFile).c_str() );
if (xml == NULL)
{
@@ -82,15 +84,17 @@ void ModalDialog::loadFromFile(const char* xmlFile)
// ----------------------------------------------------------------------------
void ModalDialog::doInit(const float percentWidth, const float percentHeight)
void ModalDialog::doInit()
{
if(m_init) return;
m_init = true;
pointer_was_shown = irr_driver->isPointerShown();
irr_driver->showPointer();
const core::dimension2d<u32>& frame_size = GUIEngine::getDriver()->getCurrentRenderTargetSize();
const int w = (int)(frame_size.Width*percentWidth);
const int h = (int)(frame_size.Height*percentHeight);
const int w = (int)(frame_size.Width* m_percent_width);
const int h = (int)(frame_size.Height* m_percent_height);
assert(frame_size.Width > 0);
assert(frame_size.Height > 0);
@@ -187,6 +191,8 @@ void ModalDialog::dismiss()
{
if(modalWindow != NULL) delete modalWindow;
modalWindow = NULL;
if(GUIEngine::getCurrentScreen() != NULL)
GUIEngine::getCurrentScreen()->onDialogClose();
}
// ----------------------------------------------------------------------------

View File

@@ -55,11 +55,12 @@ namespace GUIEngine
class ModalDialog : public SkinWidgetContainer, public AbstractTopLevelContainer
{
private:
/** Because C++ doesn't support constructor delegation... */
void doInit(const float percentWidth, const float percentHeight);
ModalDialogLocation m_dialog_location;
float m_percent_width, m_percent_height;
bool m_init;
protected:
irr::gui::IGUIWindow* m_irrlicht_window;
@@ -85,10 +86,15 @@ namespace GUIEngine
* that takes a XML file as argument is used)
*/
virtual void loadedFromFile() {}
void doInit();
public:
LEAK_CHECK()
/** Because C++ doesn't support constructor delegation... */
bool isInited() {return m_init;}
virtual ~ModalDialog();
/** Returns whether to block event propagation (usually, you will want to block events you processed) */
@@ -105,7 +111,7 @@ namespace GUIEngine
static bool isADialogActive();
/** Override to change what happens on escape pressed */
virtual void escapePressed() { dismiss(); }
virtual bool onEscapePressed() { return true; }
/** Override to be notified of updates */
virtual void onUpdate(float dt) { }
@@ -115,6 +121,7 @@ namespace GUIEngine
* init(), which is invoked afer widgets were added)
*/
virtual void beforeAddingWidgets() {}
virtual void load() {}
/** \brief Optional callback invoked after widgets have been add()ed */
virtual void init() {}

View File

@@ -32,7 +32,6 @@ ScalableFont::ScalableFont(IGUIEnvironment *env, const io::path& filename)
m_fallback_kerning_width = 0;
m_fallback_font_scale = 1.0f;
m_scale = 1.0f;
m_tab_stop = 0.5f;
m_is_hollow_copy = false;
m_black_border = false;
m_shadow = false;
@@ -500,15 +499,12 @@ void ScalableFont::draw(const core::stringw& text,
core::position2d<s32> offset = position.UpperLeftCorner;
core::dimension2d<s32> text_dimension;
// When we use the "tab" hack, disable right-alignment, it messes up everything
bool has_tab = (text.findFirst(L'\t') != -1);
if ((m_rtl && !has_tab) || hcenter || vcenter || clip)
if (m_rtl || hcenter || vcenter || clip)
{
text_dimension = getDimension(text.c_str());
if (hcenter) offset.X += (position.getWidth() - text_dimension.Width) / 2;
else if (m_rtl && !has_tab) offset.X += (position.getWidth() - text_dimension.Width);
if (hcenter) offset.X += (position.getWidth() - text_dimension.Width) / 2;
else if (m_rtl) offset.X += (position.getWidth() - text_dimension.Width);
if (vcenter) offset.Y += (position.getHeight() - text_dimension.Height) / 2;
if (clip)
@@ -519,14 +515,6 @@ void ScalableFont::draw(const core::stringw& text,
}
}
if (m_rtl && has_tab)
{
const int where = text.findFirst(L'\t');
core::stringw substr = text.subString(0, where-1);
text_dimension = getDimension(substr.c_str()) + getDimension(L"XX");
offset.X += (int)(position.getWidth()*m_tab_stop-text_dimension.Width);
}
// ---- collect character locations
const unsigned int text_size = text.size();
core::array<s32> indices(text_size);
@@ -537,14 +525,6 @@ void ScalableFont::draw(const core::stringw& text,
{
wchar_t c = text[i];
//hack: one tab character is supported, it moves the cursor to the tab stop
if (c == L'\t')
{
offset.X = (int)(position.UpperLeftCorner.X +
position.getWidth()*m_tab_stop);
continue;
}
if (c == L'\r' || // Windows breaks
c == L'\n' ) // Unix breaks
{

View File

@@ -61,9 +61,6 @@ class ScalableFont : public IGUIFontBitmap
bool m_is_hollow_copy;
bool m_rtl;
/** Position in range [0..1] of the single tab stop we support */
float m_tab_stop;
public:
LEAK_CHECK()
@@ -145,9 +142,6 @@ public:
void updateRTL();
/** \param pos position of the tab stop, in range [0..1] */
void setTabStop(float pos) { m_tab_stop = pos; }
private:
struct SFontArea

View File

@@ -61,6 +61,7 @@ namespace GUIEngine
template<typename SCREEN>
class ScreenSingleton
{
protected:
static SCREEN* singleton;
public:
@@ -302,6 +303,10 @@ namespace GUIEngine
int axisDir,
int value) {}
/** Callback that gets called when a dialog is closed.
* Can be used to set focus for instance.
*/
virtual void onDialogClose() {}
};
}

View File

@@ -814,14 +814,13 @@ void Skin::drawProgress(Widget* w, const core::recti &rect,
void Skin::drawRatingBar(Widget *w, const core::recti &rect,
const bool pressed, const bool focused)
{
static const int step_number = 3; // Harcoded number of step.
RatingBarWidget *ratingBar = (RatingBarWidget*)w;
const ITexture *texture = SkinConfig::m_render_params["rating::neutral"].getImage();
const int texture_w = texture->getSize().Width / 4;
const int texture_h = texture->getSize().Height;
const float aspect_ratio = 1.0f;
RatingBarWidget *ratingBar = (RatingBarWidget*)w;
const int star_number = ratingBar->getStarNumber();
int star_h = rect.getHeight();
@@ -835,8 +834,18 @@ void Skin::drawRatingBar(Widget *w, const core::recti &rect,
}
// center horizontally and vertically
const int x_from = rect.UpperLeftCorner.X + (rect.getWidth() - star_w) / 2;
const int y_from = rect.UpperLeftCorner.Y + (rect.getHeight() - star_h) / 2;
const int x_from = rect.UpperLeftCorner.X;
const int y_from = rect.UpperLeftCorner.Y;
core::recti stars_rect(x_from, y_from, x_from + (star_number * star_w), y_from + star_h);
if(!w->m_deactivated)
ratingBar->setStepValuesByMouse(irr_driver->getDevice()->getCursorControl()->getPosition(), stars_rect);
SColor colors[] = { SColor(100,255,255,255),
SColor(100,255,255,255),
SColor(100,255,255,255),
SColor(100,255,255,255) };
for (int i = 0; i < star_number; i++)
{
@@ -847,14 +856,15 @@ void Skin::drawRatingBar(Widget *w, const core::recti &rect,
star_rect.LowerRightCorner.X = x_from + (i + 1) * star_w;
star_rect.LowerRightCorner.Y = y_from + star_h;
int step = ratingBar->getStepOfStar(i, step_number);
int step = ratingBar->getStepsOfStar(i);
const core::recti source_area(texture_w * step, 0,
texture_w * (step + 1), texture_h);
GUIEngine::getDriver()->draw2DImage(texture,
star_rect, source_area,
0 /* no clipping */, 0,
0 /* no clipping */,
(w->m_deactivated || ID_DEBUG) ? colors : 0,
true /* alpha */);
}

View File

@@ -94,6 +94,7 @@ Widget::Widget(WidgetType type, bool reserve_id)
m_reserved_id = -1;
m_deactivated = false;
m_is_visible = true;
m_badges = 0;
// set a default value, derivates can override this as they wish
@@ -315,7 +316,18 @@ void Widget::setParent(IGUIElement* parent)
bool Widget::isVisible() const
{
return m_element && m_element->isVisible();
if (m_element != NULL)
assert(m_element->isVisible() == m_is_visible);
return m_is_visible;
}
// -----------------------------------------------------------------------------
bool Widget::isActivated() const
{
if (isVisible())
return !m_deactivated;
return false;
}
// -----------------------------------------------------------------------------
@@ -326,6 +338,7 @@ void Widget::setVisible(bool visible)
{
m_element->setVisible(visible);
}
m_is_visible = visible;
m_deactivated = !visible;
const int childrenCount = m_children.size();
@@ -345,4 +358,3 @@ void Widget::moveIrrlichtElement()
irr::core::dimension2di(m_w, m_h) ) );
}
}

View File

@@ -235,9 +235,12 @@ namespace GUIEngine
/** A bitmask of which badges to show, if any; choices are *_BADGE, defined above */
int m_badges;
/** A simple flag that can be raised to hide this widget */
/** A simple flag that can be raised to deactivate this widget */
bool m_deactivated;
/** A flag to indicate whether this widget should be visible or not. */
bool m_is_visible;
/** Set to false if widget is something that should not receive focus */
bool m_focusable;
@@ -324,6 +327,8 @@ namespace GUIEngine
/** Returns if the element is visible. */
bool isVisible() const;
bool isActivated() const;
/**
* Call to resize/move the widget. Not all widgets can resize gracefully.
*/
@@ -646,6 +651,9 @@ namespace GUIEngine
*/
bool ok() const { return (m_magic_number == 0xCAFEC001); }
/** Gets called when the widget is active and got clicked. (Only works for button widgets for now.) */
virtual void onClick() { }
};

View File

@@ -0,0 +1,757 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// 2013 Glenn De Jonghe
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "guiengine/widgets/CGUISTKListBox.h"
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IVideoDriver.h"
#include "IGUIFont.h"
#include "IGUISpriteBank.h"
#include "IGUIScrollBar.h"
#include "utils/time.hpp"
namespace irr
{
namespace gui
{
//! constructor
CGUISTKListBox::CGUISTKListBox(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle, bool clip,
bool drawBack, bool moveOverSelect)
: IGUIElement(EGUIET_LIST_BOX, environment, parent, id, rectangle), Selected(-1),
ItemHeight(0),ItemHeightOverride(0),
TotalItemHeight(0), ItemsIconWidth(0), Font(0), IconBank(0),
ScrollBar(0), selectTime(0), LastKeyTime(0), Selecting(false), DrawBack(drawBack),
MoveOverSelect(moveOverSelect), AutoScroll(true), HighlightWhenNotFocused(true)
{
#ifdef _DEBUG
setDebugName("CGUISTKListBox");
#endif
IGUISkin* skin = Environment->getSkin();
const s32 s = skin->getSize(EGDS_SCROLLBAR_SIZE);
ScrollBar = Environment->addScrollBar(false,
core::rect<s32>(RelativeRect.getWidth() - s, 0,
RelativeRect.getWidth(), RelativeRect.getHeight()), this, -1);
ScrollBar->grab();
ScrollBar->setSubElement(true);
ScrollBar->setTabStop(false);
ScrollBar->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
ScrollBar->setVisible(false);
ScrollBar->setPos(0);
setNotClipped(!clip);
// this element can be tabbed to
setTabStop(true);
setTabOrder(-1);
updateAbsolutePosition();
}
//! destructor
CGUISTKListBox::~CGUISTKListBox()
{
if (ScrollBar)
ScrollBar->drop();
if (Font)
Font->drop();
if (IconBank)
IconBank->drop();
}
//! returns amount of list items
u32 CGUISTKListBox::getItemCount() const
{
return Items.size();
}
const wchar_t* CGUISTKListBox::getCellText(u32 row_num, u32 col_num) const
{
if ( row_num >= Items.size() )
return 0;
if ( col_num >= Items[row_num].m_contents.size() )
return 0;
return Items[row_num].m_contents[col_num].m_text.c_str();
}
CGUISTKListBox::ListItem CGUISTKListBox::getItem(u32 id) const
{
return Items[id];
}
//! Returns the icon of an item
s32 CGUISTKListBox::getIcon(u32 row_num, u32 col_num) const
{
if ( row_num >= Items.size() )
return -1;
if ( col_num >= Items[row_num].m_contents.size() )
return -1;
return Items[row_num].m_contents[col_num].m_icon;
}
void CGUISTKListBox::removeItem(u32 id)
{
if (id >= Items.size())
return;
if ((u32)Selected==id)
{
Selected = -1;
}
else if ((u32)Selected > id)
{
Selected -= 1;
selectTime = (u32)StkTime::getTimeSinceEpoch();
}
Items.erase(id);
recalculateItemHeight();
}
s32 CGUISTKListBox::getItemAt(s32 xpos, s32 ypos) const
{
if ( xpos < AbsoluteRect.UpperLeftCorner.X || xpos >= AbsoluteRect.LowerRightCorner.X
|| ypos < AbsoluteRect.UpperLeftCorner.Y || ypos >= AbsoluteRect.LowerRightCorner.Y
)
return -1;
if ( ItemHeight == 0 )
return -1;
s32 item = ((ypos - AbsoluteRect.UpperLeftCorner.Y - 1) + ScrollBar->getPos()) / ItemHeight;
if ( item < 0 || item >= (s32)Items.size())
return -1;
return item;
}
//! clears the list
void CGUISTKListBox::clear()
{
Items.clear();
ItemsIconWidth = 0;
Selected = -1;
if (ScrollBar)
ScrollBar->setPos(0);
recalculateItemHeight();
}
void CGUISTKListBox::recalculateItemHeight()
{
IGUISkin* skin = Environment->getSkin();
if (Font != skin->getFont())
{
if (Font)
Font->drop();
Font = skin->getFont();
if ( 0 == ItemHeightOverride )
ItemHeight = 0;
if (Font)
{
if ( 0 == ItemHeightOverride )
ItemHeight = Font->getDimension(L"A").Height + 4;
Font->grab();
}
}
TotalItemHeight = ItemHeight * Items.size();
ScrollBar->setMax( core::max_(0, TotalItemHeight - AbsoluteRect.getHeight()) );
s32 minItemHeight = ItemHeight > 0 ? ItemHeight : 1;
ScrollBar->setSmallStep ( minItemHeight );
ScrollBar->setLargeStep ( 2*minItemHeight );
if ( TotalItemHeight <= AbsoluteRect.getHeight() )
ScrollBar->setVisible(false);
else
ScrollBar->setVisible(true);
}
//! returns id of selected item. returns -1 if no item is selected.
s32 CGUISTKListBox::getSelected() const
{
return Selected;
}
//! sets the selected item. Set this to -1 if no item should be selected
void CGUISTKListBox::setSelected(s32 id)
{
if ((u32)id>=Items.size())
Selected = -1;
else
Selected = id;
selectTime = (u32)StkTime::getTimeSinceEpoch();
recalculateScrollPos();
}
s32 CGUISTKListBox::getRowByCellText(const wchar_t * text)
{
s32 row_index = -1;
s32 col_index = -1;
if (text)
{
for ( row_index = 0; row_index < (s32) Items.size(); ++row_index )
{
for ( col_index = 0; col_index < (s32) Items[row_index].m_contents.size(); ++col_index )
{
if ( Items[row_index].m_contents[col_index].m_text == text ) return row_index;
}
}
}
return -1;
}
//! sets the selected item. Set this to -1 if no item should be selected
void CGUISTKListBox::setSelectedByCellText(const wchar_t * text)
{
setSelected(getRowByCellText(text));
}
s32 CGUISTKListBox::getRowByInternalName(const std::string & text) const
{
s32 row_index = -1;
if (text != "")
{
for ( row_index = 0; row_index < (s32) Items.size(); ++row_index )
{
if (Items[row_index].m_internal_name == text) return row_index;
}
}
return -1;
}
//! called if an event happened.
bool CGUISTKListBox::OnEvent(const SEvent& event)
{
if (isEnabled())
{
switch(event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (event.KeyInput.PressedDown &&
(event.KeyInput.Key == KEY_DOWN ||
event.KeyInput.Key == KEY_UP ||
event.KeyInput.Key == KEY_HOME ||
event.KeyInput.Key == KEY_END ||
event.KeyInput.Key == KEY_NEXT ||
event.KeyInput.Key == KEY_PRIOR ) )
{
s32 oldSelected = Selected;
switch (event.KeyInput.Key)
{
case KEY_DOWN:
Selected += 1;
break;
case KEY_UP:
Selected -= 1;
break;
case KEY_HOME:
Selected = 0;
break;
case KEY_END:
Selected = (s32)Items.size()-1;
break;
case KEY_NEXT:
Selected += AbsoluteRect.getHeight() / ItemHeight;
break;
case KEY_PRIOR:
Selected -= AbsoluteRect.getHeight() / ItemHeight;
break;
default:
break;
}
if (Selected >= (s32)Items.size())
Selected = Items.size() - 1;
else
if (Selected<0)
Selected = 0;
recalculateScrollPos();
// post the news
if (oldSelected != Selected && Parent && !Selecting && !MoveOverSelect)
{
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = this;
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = EGET_LISTBOX_CHANGED;
Parent->OnEvent(e);
}
return true;
}
else
if (!event.KeyInput.PressedDown && ( event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE ) )
{
if (Parent)
{
SEvent e;
e.EventType = EET_GUI_EVENT;
e.GUIEvent.Caller = this;
e.GUIEvent.Element = 0;
e.GUIEvent.EventType = EGET_LISTBOX_SELECTED_AGAIN;
Parent->OnEvent(e);
}
return true;
}
break;
case EET_GUI_EVENT:
switch(event.GUIEvent.EventType)
{
case gui::EGET_SCROLL_BAR_CHANGED:
if (event.GUIEvent.Caller == ScrollBar)
return true;
break;
case gui::EGET_ELEMENT_FOCUS_LOST:
{
if (event.GUIEvent.Caller == this)
Selecting = false;
break;
}
default:
break;
}
break;
case EET_MOUSE_INPUT_EVENT:
{
core::position2d<s32> p(event.MouseInput.X, event.MouseInput.Y);
switch(event.MouseInput.Event)
{
case EMIE_MOUSE_WHEEL:
ScrollBar->setPos(ScrollBar->getPos() + (event.MouseInput.Wheel < 0 ? -1 : 1)*-ItemHeight/2);
return true;
case EMIE_LMOUSE_PRESSED_DOWN:
{
Selecting = true;
return true;
}
case EMIE_LMOUSE_LEFT_UP:
{
Selecting = false;
if (isPointInside(p))
selectNew(event.MouseInput.Y);
return true;
}
case EMIE_MOUSE_MOVED:
if (Selecting || MoveOverSelect)
{
if (isPointInside(p))
{
selectNew(event.MouseInput.Y, true);
return true;
}
}
default:
break;
}
}
break;
case EET_LOG_TEXT_EVENT:
case EET_USER_EVENT:
case EET_JOYSTICK_INPUT_EVENT:
case EGUIET_FORCE_32_BIT:
break;
}
}
return IGUIElement::OnEvent(event);
}
void CGUISTKListBox::selectNew(s32 ypos, bool onlyHover)
{
u32 now = (u32)StkTime::getTimeSinceEpoch();
s32 oldSelected = Selected;
Selected = getItemAt(AbsoluteRect.UpperLeftCorner.X, ypos);
if (Selected<0 && !Items.empty())
Selected = 0;
recalculateScrollPos();
gui::EGUI_EVENT_TYPE eventType = (Selected == oldSelected && now < selectTime + 500) ? EGET_LISTBOX_SELECTED_AGAIN : EGET_LISTBOX_CHANGED;
selectTime = now;
// post the news
if (Parent && !onlyHover)
{
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = 0;
event.GUIEvent.EventType = eventType;
Parent->OnEvent(event);
}
}
//! Update the position and size of the listbox, and update the scrollbar
void CGUISTKListBox::updateAbsolutePosition()
{
IGUIElement::updateAbsolutePosition();
recalculateItemHeight();
}
//! draws the element and its children
void CGUISTKListBox::draw()
{
if (!IsVisible)
return;
recalculateItemHeight(); // if the font changed
IGUISkin* skin = Environment->getSkin();
core::rect<s32>* clipRect = 0;
// draw background
core::rect<s32> frameRect(AbsoluteRect);
// draw items
core::rect<s32> clientClip(AbsoluteRect);
clientClip.UpperLeftCorner.Y += 1;
clientClip.UpperLeftCorner.X += 1;
if (ScrollBar->isVisible())
clientClip.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE);
clientClip.LowerRightCorner.Y -= 1;
clientClip.clipAgainst(AbsoluteClippingRect);
skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_HIGH_LIGHT), true,
DrawBack, frameRect, &clientClip);
if (clipRect)
clientClip.clipAgainst(*clipRect);
frameRect = AbsoluteRect;
frameRect.UpperLeftCorner.X += 1;
if (ScrollBar->isVisible())
frameRect.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE);
frameRect.LowerRightCorner.Y = AbsoluteRect.UpperLeftCorner.Y + ItemHeight;
frameRect.UpperLeftCorner.Y -= ScrollBar->getPos();
frameRect.LowerRightCorner.Y -= ScrollBar->getPos();
bool hl = (HighlightWhenNotFocused || Environment->hasFocus(this) || Environment->hasFocus(ScrollBar));
for (s32 i=0; i<(s32)Items.size(); ++i)
{
if (frameRect.LowerRightCorner.Y >= AbsoluteRect.UpperLeftCorner.Y &&
frameRect.UpperLeftCorner.Y <= AbsoluteRect.LowerRightCorner.Y)
{
if (i == Selected && hl)
skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), frameRect, &clientClip);
core::rect<s32> textRect = frameRect;
if (Font)
{
int total_proportion = 0;
for(unsigned int x = 0; x < Items[i].m_contents.size(); ++x)
{
total_proportion += Items[i].m_contents[x].m_proportion;
}
int part_size = (int)(textRect.getWidth() / float(total_proportion));
for(unsigned int x = 0; x < Items[i].m_contents.size(); ++x)
{
textRect.LowerRightCorner.X = textRect.UpperLeftCorner.X +
(Items[i].m_contents[x].m_proportion * part_size);
textRect.UpperLeftCorner.X += 3;
if (IconBank && (Items[i].m_contents[x].m_icon > -1))
{
core::position2di iconPos = textRect.UpperLeftCorner;
iconPos.Y += textRect.getHeight() / 2;
iconPos.X += ItemsIconWidth/2;
if ( i==Selected && hl )
{
IconBank->draw2DSprite(
(u32)Items[i].m_contents[x].m_icon,
iconPos, &clientClip,
hasItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) ?
getItemOverrideColor(i, EGUI_LBC_ICON_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_ICON_HIGHLIGHT),
selectTime, (u32)StkTime::getTimeSinceEpoch(), false, true);
}
else
{
IconBank->draw2DSprite(
(u32)Items[i].m_contents[x].m_icon,
iconPos,
&clientClip,
hasItemOverrideColor(i, EGUI_LBC_ICON) ? getItemOverrideColor(i, EGUI_LBC_ICON) : getItemDefaultColor(EGUI_LBC_ICON),
0 , (i==Selected) ? (u32)StkTime::getTimeSinceEpoch() : 0, false, true);
}
textRect.UpperLeftCorner.X += ItemsIconWidth;
}
textRect.UpperLeftCorner.X += 3;
if ( i==Selected && hl )
{
Font->draw(
Items[i].m_contents[x].m_text.c_str(),
textRect,
hasItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) ?
getItemOverrideColor(i, EGUI_LBC_TEXT_HIGHLIGHT) : getItemDefaultColor(EGUI_LBC_TEXT_HIGHLIGHT),
Items[i].m_contents[x].m_center, true, &clientClip);
}
else
{
Font->draw(
Items[i].m_contents[x].m_text.c_str(),
textRect,
hasItemOverrideColor(i, EGUI_LBC_TEXT) ? getItemOverrideColor(i, EGUI_LBC_TEXT) : getItemDefaultColor(EGUI_LBC_TEXT),
Items[i].m_contents[x].m_center, true, &clientClip);
}
//Position back to inital pos
textRect.UpperLeftCorner.X -= ItemsIconWidth+6;
//Calculate new beginning
textRect.UpperLeftCorner.X += Items[i].m_contents[x].m_proportion * part_size;
}
}
}
frameRect.UpperLeftCorner.Y += ItemHeight;
frameRect.LowerRightCorner.Y += ItemHeight;
}
IGUIElement::draw();
}
//! adds an list item with an icon
u32 CGUISTKListBox::addItem(const ListItem & item)
{
Items.push_back(item);
recalculateItemHeight();
recalculateIconWidth();
return Items.size() - 1;
}
void CGUISTKListBox::setSpriteBank(IGUISpriteBank* bank)
{
if ( bank == IconBank )
return;
if (IconBank)
IconBank->drop();
IconBank = bank;
if (IconBank)
IconBank->grab();
}
void CGUISTKListBox::recalculateScrollPos()
{
if (!AutoScroll)
return;
const s32 selPos = (Selected == -1 ? TotalItemHeight : Selected * ItemHeight) - ScrollBar->getPos();
if (selPos < 0)
{
ScrollBar->setPos(ScrollBar->getPos() + selPos);
}
else
if (selPos > AbsoluteRect.getHeight() - ItemHeight)
{
ScrollBar->setPos(ScrollBar->getPos() + selPos - AbsoluteRect.getHeight() + ItemHeight);
}
}
void CGUISTKListBox::setAutoScrollEnabled(bool scroll)
{
AutoScroll = scroll;
}
bool CGUISTKListBox::isAutoScrollEnabled() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return AutoScroll;
}
void CGUISTKListBox::recalculateIconWidth()
{
for(int x = 0; x < (int)Items.getLast().m_contents.size(); ++x)
{
s32 icon = Items.getLast().m_contents[x].m_icon;
if (IconBank && icon > -1 &&
IconBank->getSprites().size() > (u32)icon &&
IconBank->getSprites()[(u32)icon].Frames.size())
{
u32 rno = IconBank->getSprites()[(u32)icon].Frames[0].rectNumber;
if (IconBank->getPositions().size() > rno)
{
const s32 w = IconBank->getPositions()[rno].getWidth();
if (w > ItemsIconWidth)
ItemsIconWidth = w;
}
}
}
}
void CGUISTKListBox::setCell(u32 row_num, u32 col_num, const wchar_t* text, s32 icon)
{
if ( row_num >= Items.size() )
return;
if ( col_num >= Items[row_num].m_contents.size() )
return;
Items[row_num].m_contents[col_num].m_text = text;
Items[row_num].m_contents[col_num].m_icon = icon;
recalculateItemHeight();
recalculateIconWidth();
}
void CGUISTKListBox::swapItems(u32 index1, u32 index2)
{
if ( index1 >= Items.size() || index2 >= Items.size() )
return;
ListItem dummmy = Items[index1];
Items[index1] = Items[index2];
Items[index2] = dummmy;
}
void CGUISTKListBox::setItemOverrideColor(u32 index, video::SColor color)
{
for ( u32 c=0; c < EGUI_LBC_COUNT; ++c )
{
Items[index].OverrideColors[c].Use = true;
Items[index].OverrideColors[c].Color = color;
}
}
void CGUISTKListBox::setItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType, video::SColor color)
{
if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT )
return;
Items[index].OverrideColors[colorType].Use = true;
Items[index].OverrideColors[colorType].Color = color;
}
void CGUISTKListBox::clearItemOverrideColor(u32 index)
{
for (u32 c=0; c < (u32)EGUI_LBC_COUNT; ++c )
{
Items[index].OverrideColors[c].Use = false;
}
}
void CGUISTKListBox::clearItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType)
{
if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT )
return;
Items[index].OverrideColors[colorType].Use = false;
}
bool CGUISTKListBox::hasItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const
{
if ( index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT )
return false;
return Items[index].OverrideColors[colorType].Use;
}
video::SColor CGUISTKListBox::getItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const
{
if ( (u32)index >= Items.size() || colorType < 0 || colorType >= EGUI_LBC_COUNT )
return video::SColor();
return Items[index].OverrideColors[colorType].Color;
}
video::SColor CGUISTKListBox::getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) const
{
IGUISkin* skin = Environment->getSkin();
if ( !skin )
return video::SColor();
switch ( colorType )
{
case EGUI_LBC_TEXT:
return skin->getColor(EGDC_BUTTON_TEXT);
case EGUI_LBC_TEXT_HIGHLIGHT:
return skin->getColor(EGDC_HIGH_LIGHT_TEXT);
case EGUI_LBC_ICON:
return skin->getColor(EGDC_ICON);
case EGUI_LBC_ICON_HIGHLIGHT:
return skin->getColor(EGDC_ICON_HIGH_LIGHT);
default:
return video::SColor();
}
}
//! set global itemHeight
void CGUISTKListBox::setItemHeight( s32 height )
{
ItemHeight = height;
ItemHeightOverride = 1;
}
//! Sets whether to draw the background
void CGUISTKListBox::setDrawBackground(bool draw)
{
DrawBack = draw;
}
} // end namespace gui
} // end namespace irr

View File

@@ -0,0 +1,198 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// 2013 Glenn De Jonghe
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef HEADER_CGUISTKListBox_HPP
#define HEADER_CGUISTKListBox_HPP
#include "IrrCompileConfig.h"
#include "IGUIListBox.h"
#include "IGUIElement.h"
#include "irrArray.h"
#include <string>
namespace irr
{
namespace gui
{
class IGUIFont;
class IGUIScrollBar;
class CGUISTKListBox : public IGUIElement
{
public:
struct ListItem
{
struct ListCell
{
irr::core::stringw m_text;
int m_proportion;
s32 m_icon;
bool m_center;
ListCell(irr::core::stringw text, s32 icon = -1, int proportion = 1, bool center = false)
{
m_text = text;
m_proportion = proportion;
m_icon = icon;
m_center = center;
}
};
core::array< ListCell > m_contents;
// Actually only used in list_widget -- still refactoring FIXME
std::string m_internal_name;
int m_current_id;
// A multicolor extension
struct ListItemOverrideColor
{
ListItemOverrideColor() : Use(false) {}
bool Use;
video::SColor Color;
};
ListItemOverrideColor OverrideColors[EGUI_LBC_COUNT];
};
//! constructor
CGUISTKListBox(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle, bool clip=true,
bool drawBack=false, bool moveOverSelect=false);
//! destructor
virtual ~CGUISTKListBox();
//! returns amount of list items
virtual u32 getItemCount() const;
virtual const wchar_t* getCellText(u32 row_num, u32 col_num) const;
virtual ListItem getItem(u32 id) const;
//! clears the list
virtual void clear();
//! returns id of selected item. returns -1 if no item is selected.
virtual s32 getSelected() const;
//! sets the selected item. Set this to -1 if no item should be selected
virtual void setSelected(s32 id);
virtual s32 getRowByCellText(const wchar_t * text);
//! sets the selected item. Set this to -1 if no item should be selected
virtual void setSelectedByCellText(const wchar_t * text);
virtual s32 getRowByInternalName(const std::string & text) const;
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
//! draws the element and its children
virtual void draw();
//! adds an list item with an icon
//! \param text Text of list entry
//! \param icon Sprite index of the Icon within the current sprite bank. Set it to -1 if you want no icon
//! \return
//! returns the id of the new created item
//virtual u32 addItem(const wchar_t* text, s32 icon);
virtual u32 addItem(const ListItem & item);
//! Returns the icon of an item
virtual s32 getIcon(u32 row_num, u32 col_num) const;
//! removes an item from the list
virtual void removeItem(u32 id);
//! get the the id of the item at the given absolute coordinates
virtual s32 getItemAt(s32 xpos, s32 ypos) const;
//! Sets the sprite bank which should be used to draw list icons. This font is set to the sprite bank of
//! the built-in-font by default. A sprite can be displayed in front of every list item.
//! An icon is an index within the icon sprite bank. Several default icons are available in the
//! skin through getIcon
virtual void setSpriteBank(IGUISpriteBank* bank);
//! set whether the listbox should scroll to newly selected items
virtual void setAutoScrollEnabled(bool scroll);
//! returns true if automatic scrolling is enabled, false if not.
virtual bool isAutoScrollEnabled() const;
//! Update the position and size of the listbox, and update the scrollbar
virtual void updateAbsolutePosition();
//! set all item colors at given index to color
virtual void setItemOverrideColor(u32 index, video::SColor color);
//! set all item colors of specified type at given index to color
virtual void setItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType, video::SColor color);
//! clear all item colors at index
virtual void clearItemOverrideColor(u32 index);
//! clear item color at index for given colortype
virtual void clearItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType);
//! has the item at index its color overwritten?
virtual bool hasItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const;
//! return the overwrite color at given item index.
virtual video::SColor getItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const;
//! return the default color which is used for the given colorType
virtual video::SColor getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) const;
//! set the item at the given index
virtual void setCell(u32 row_num, u32 col_num, const wchar_t* text, s32 icon);
//! Swap the items at the given indices
virtual void swapItems(u32 index1, u32 index2);
//! set global itemHeight
virtual void setItemHeight( s32 height );
//! Sets whether to draw the background
virtual void setDrawBackground(bool draw);
private:
void recalculateItemHeight();
void selectNew(s32 ypos, bool onlyHover=false);
void recalculateScrollPos();
// extracted that function to avoid copy&paste code
void recalculateIconWidth();
core::array< ListItem > Items;
s32 Selected;
s32 ItemHeight;
s32 ItemHeightOverride;
s32 TotalItemHeight;
s32 ItemsIconWidth;
gui::IGUIFont* Font;
gui::IGUISpriteBank* IconBank;
gui::IGUIScrollBar* ScrollBar;
u32 selectTime;
u32 LastKeyTime;
core::stringw KeyBuffer;
bool Selecting;
bool DrawBack;
bool MoveOverSelect;
bool AutoScroll;
bool HighlightWhenNotFocused;
};
} // end namespace gui
} // end namespace irr
#endif

View File

@@ -39,15 +39,17 @@ using namespace irr;
LabelWidget::LabelWidget(bool title, bool bright) : Widget(WTYPE_LABEL)
{
m_title_font = title;
m_has_color = false;
m_scroll_speed = 0;
m_scroll_offset = 0;
m_bright = bright;
if (bright)
if (m_bright)
{
m_has_color = true;
m_color = Skin::getColor("brighttext::neutral");
}
else
m_has_color = false;
} // LabelWidget
// ----------------------------------------------------------------------------
@@ -131,7 +133,6 @@ void LabelWidget::setText(const wchar_t *text, bool expandIfNeeded)
if (expandIfNeeded)
{
assert(m_element != NULL);
const int fwidth = (m_title_font ? GUIEngine::getTitleFont() : GUIEngine::getFont())->getDimension(text).Width;
core::rect<s32> rect = m_element->getRelativePosition();
@@ -173,7 +174,6 @@ bool LabelWidget::scrolledOff() const
{
// This method may only be called after this widget has been add()ed
assert(m_element != NULL);
return m_scroll_offset <= -m_element->getAbsolutePosition().getWidth();
}
@@ -185,3 +185,38 @@ void LabelWidget::setScrollSpeed(float speed)
m_scroll_speed = speed;
} // setScrollSpeed
// ----------------------------------------------------------------------------
void LabelWidget::setColor(const irr::video::SColor& color)
{
assert(m_element != NULL);
m_color = color;
m_has_color = true;
((IGUIStaticText*)m_element)->setOverrideColor(m_color);
}
// ----------------------------------------------------------------------------
void LabelWidget::setErrorColor()
{
setColor(irr::video::SColor(255, 255, 0, 0));
}
// ----------------------------------------------------------------------------
void LabelWidget::setDefaultColor()
{
if (m_bright)
{
setColor(Skin::getColor("brighttext::neutral"));
}
else
{
if(m_has_color)
{
assert(m_element != NULL);
m_has_color = false;
((IGUIStaticText*)m_element)->enableOverrideColor(false);
}
}
}
// ----------------------------------------------------------------------------

View File

@@ -34,6 +34,7 @@ namespace GUIEngine
*/
class LabelWidget : public Widget
{
bool m_bright;
bool m_has_color;
irr::video::SColor m_color;
@@ -58,14 +59,12 @@ namespace GUIEngine
/** \brief Callback from base class Widget */
virtual void add();
/** Sets the color of the widget.
/** Sets the color of the widget.
* \param color The color to use for this widget. */
void setColor(const irr::video::SColor& color)
{
m_color = color;
m_has_color = true;
} // setColor
void setColor(const irr::video::SColor& color);
void setErrorColor();
void setDefaultColor();
/** \brief Callback from base class Widget */
virtual void update(float dt);
@@ -87,11 +86,11 @@ namespace GUIEngine
virtual void setText(const wchar_t *text, bool expandAsNeeded);
/** Overloaded function which takes a stringw. */
virtual void setText(const irr::core::stringw &s, bool expandAsNeeded)
virtual void setText(const irr::core::stringw &s, bool expandAsNeeded)
{
setText(s.c_str(), expandAsNeeded);
}
// --------------------------------------------------------------------
/** Sets horizontal scroll speed. */

View File

@@ -15,14 +15,16 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "guiengine/widgets/list_widget.hpp"
#include "guiengine/CGUISpriteBank.h"
#include "guiengine/engine.hpp"
#include "guiengine/widgets/list_widget.hpp"
#include "io/file_manager.hpp"
#include <IGUIElement.h>
#include <IGUISkin.h>
#include <IGUIEnvironment.h>
#include <IGUIListBox.h>
#include "IGUIFontBitmap.h"
#include <sstream>
@@ -51,7 +53,7 @@ void ListWidget::setIcons(STKModifiedSpriteBank* icons, int size)
if (m_use_icons)
{
IGUIListBox* list = getIrrlichtElement<IGUIListBox>();
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
assert(list != NULL);
list->setSpriteBank(m_icons);
@@ -81,8 +83,8 @@ void ListWidget::setIcons(STKModifiedSpriteBank* icons, int size)
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
void ListWidget::add()
{
const int header_height = GUIEngine::getFontHeight() + 15;
@@ -90,11 +92,32 @@ void ListWidget::add()
rect<s32> widget_size = (m_header.size() > 0 ? rect<s32>(m_x, m_y + header_height, m_x + m_w, m_y + m_h) :
rect<s32>(m_x, m_y, m_x + m_w, m_y + m_h) );
IGUIListBox* list = GUIEngine::getGUIEnv()->addListBox (widget_size, m_parent, getNewID());
list->setAutoScrollEnabled(false);
IGUISkin * current_skin = GUIEngine::getGUIEnv()->getSkin();
IGUIFont * current_font = GUIEngine::getGUIEnv()->getBuiltInFont();
CGUISTKListBox * list_box = new CGUISTKListBox(
GUIEngine::getGUIEnv(),
m_parent ? m_parent : GUIEngine::getGUIEnv()->getRootGUIElement(),
getNewID(),
widget_size,
true,
true,
false);
m_element = list;
m_element->setTabOrder( list->getID() );
if (current_skin && current_skin->getSpriteBank())
{
list_box->setSpriteBank(current_skin->getSpriteBank());
}
else if (current_font && current_font->getType() == EGFT_BITMAP)
{
list_box->setSpriteBank( ((IGUIFontBitmap*)current_font)->getSpriteBank());
}
list_box->drop();
list_box->setAutoScrollEnabled(false);
m_element = list_box;
m_element->setTabOrder( list_box->getID() );
if (m_header.size() > 0)
{
@@ -150,91 +173,129 @@ void ListWidget::clear()
// May only be called AFTER this widget has been add()ed
assert(m_element != NULL);
IGUIListBox* list = getIrrlichtElement<IGUIListBox>();
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
assert(list != NULL);
list->clear();
m_items.clear();
}
// -----------------------------------------------------------------------------
void ListWidget::addItem(const std::string& internalName,
const irr::core::stringw& name, const int icon)
void ListWidget::addItem( const std::string& internal_name,
const irr::core::stringw &name,
const int icon,
bool center)
{
// May only be called AFTER this widget has been add()ed
assert(m_element != NULL);
ListCell cell(name, icon, 1, center);
ListItem newItem;
newItem.m_internal_name = internal_name;
newItem.m_contents.push_back(cell);
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
assert(list != NULL);
u32 itemID = list->addItem( newItem );
if (m_use_icons)
{
list->setItemOverrideColor( itemID, gui::EGUI_LBC_ICON, video::SColor(255,255,255,255) );
list->setItemOverrideColor( itemID, gui::EGUI_LBC_ICON_HIGHLIGHT, video::SColor(255,255,255,255) );
}
newItem.m_current_id = itemID;
}
// -----------------------------------------------------------------------------
void ListWidget::addItem(const std::string& internal_name,
PtrVector<ListCell> * contents)
{
// May only be called AFTER this widget has been add()ed
assert(m_element != NULL);
ListItem newItem;
newItem.m_label = name;
newItem.m_internal_name = internalName;
newItem.m_internal_name = internal_name;
for(int i = 0; i < (int)contents->size(); i++)
{
newItem.m_contents.push_back(*contents->get(i));
}
IGUIListBox* list = getIrrlichtElement<IGUIListBox>();
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
assert(list != NULL);
if (m_use_icons && icon != -1)
u32 itemID = list->addItem( newItem );
if (m_use_icons)
{
u32 itemID = list->addItem( name.c_str(), icon );
list->setItemOverrideColor( itemID, gui::EGUI_LBC_ICON, video::SColor(255,255,255,255) );
list->setItemOverrideColor( itemID, gui::EGUI_LBC_ICON_HIGHLIGHT, video::SColor(255,255,255,255) );
newItem.m_current_id = itemID;
}
else
{
newItem.m_current_id = list->addItem( name.c_str() );
}
m_items.push_back(newItem);
newItem.m_current_id = itemID;
}
// -----------------------------------------------------------------------------
void ListWidget::renameItem(const int itemID, const irr::core::stringw newName, const int icon)
void ListWidget::renameCell(const int row_index, const int col_index, const irr::core::stringw newName, const int icon)
{
// May only be called AFTER this widget has been add()ed
assert(m_element != NULL);
IGUIListBox* list = getIrrlichtElement<IGUIListBox>();
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
assert(list != NULL);
m_items[itemID].m_label = newName;
list->setItem(itemID, newName.c_str(), icon);
list->setCell(row_index, col_index, newName.c_str(), icon);
list->setItemOverrideColor( itemID, EGUI_LBC_TEXT , video::SColor(255,0,0,0) );
list->setItemOverrideColor( itemID, EGUI_LBC_TEXT_HIGHLIGHT, video::SColor(255,255,255,255) );
list->setItemOverrideColor( row_index, EGUI_LBC_TEXT , video::SColor(255,0,0,0) );
list->setItemOverrideColor( row_index, EGUI_LBC_TEXT_HIGHLIGHT, video::SColor(255,255,255,255) );
}
// -----------------------------------------------------------------------------
void ListWidget::renameItem(const int row_index, const irr::core::stringw newName, const int icon)
{
renameCell(row_index, 0, newName, icon);
}
// -----------------------------------------------------------------------------
void ListWidget::renameItem(const std::string & internal_name, const irr::core::stringw newName, const int icon)
{
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
assert(list != NULL);
renameCell(list->getRowByInternalName(internal_name), 0, newName, icon);
}
// -----------------------------------------------------------------------------
std::string ListWidget::getSelectionInternalName()
{
if (getSelectionID() == -1) return "";
return m_items[ getSelectionID() ].m_internal_name;
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
assert(list != NULL);
if (getSelectionID() == -1 || (getSelectionID() >= (int)list->getItemCount()))
return "";
return list->getItem(getSelectionID()).m_internal_name;
}
// -----------------------------------------------------------------------------
irr::core::stringw ListWidget::getSelectionLabel() const
irr::core::stringw ListWidget::getSelectionLabel(const int cell) const
{
const IGUIListBox* list = getIrrlichtElement<IGUIListBox>();
const CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
assert(list != NULL);
return list->getListItem( list->getSelected() );
return list->getCellText( list->getSelected(), cell);
}
// -----------------------------------------------------------------------------
void ListWidget::selectItemWithLabel(const irr::core::stringw& name)
{
IGUIListBox* list = getIrrlichtElement<IGUIListBox>();
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
assert(list != NULL);
return list->setSelected( name.c_str() );
return list->setSelectedByCellText( name.c_str() );
}
// -----------------------------------------------------------------------------
void ListWidget::unfocused(const int playerID, Widget* new_focus)
{
IGUIListBox* list = getIrrlichtElement<IGUIListBox>();
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
// remove selection when leaving list
if (list != NULL) list->setSelected(-1);
@@ -247,7 +308,7 @@ int ListWidget::getSelectionID() const
// May only be called AFTER this widget has been add()ed
assert(m_element != NULL);
return getIrrlichtElement<IGUIListBox>()->getSelected();
return getIrrlichtElement<CGUISTKListBox>()->getSelected();
}
// -----------------------------------------------------------------------------
@@ -257,7 +318,7 @@ void ListWidget::setSelectionID(const int index)
// May only be called AFTER this widget has been add()ed
assert(m_element != NULL);
IGUIListBox* irritem = getIrrlichtElement<IGUIListBox>();
CGUISTKListBox* irritem = getIrrlichtElement<CGUISTKListBox>();
// auto-scroll to item when selecting something, don't auto-scroll when selecting nothing
if (index != -1)
@@ -280,8 +341,7 @@ int ListWidget::getItemCount() const
// May only be called AFTER this widget has been add()ed
assert(m_element != NULL);
const int count = getIrrlichtElement<IGUIListBox>()->getItemCount();
assert((int)m_items.size() == count);
const int count = getIrrlichtElement<CGUISTKListBox>()->getItemCount();
return count;
}
@@ -291,7 +351,6 @@ int ListWidget::getItemCount() const
void ListWidget::elementRemoved()
{
Widget::elementRemoved();
m_items.clear();
for (int n=0; n<m_header_elements.size(); n++)
{
@@ -306,26 +365,12 @@ void ListWidget::elementRemoved()
// -----------------------------------------------------------------------------
int ListWidget::getItemID(const std::string internalName) const
{
const int count = m_items.size();
for (int i=0; i<count; i++)
{
if (m_items[i].m_internal_name == internalName) return i;
}
return -1;
}
// -----------------------------------------------------------------------------
void ListWidget::markItemRed(const int id, bool red)
{
// May only be called AFTER this widget has been add()ed
assert(m_element != NULL);
IGUIListBox* irritem = getIrrlichtElement<IGUIListBox>();
CGUISTKListBox* irritem = getIrrlichtElement<CGUISTKListBox>();
if (red)
{
@@ -346,7 +391,7 @@ void ListWidget::markItemBlue(const int id, bool blue)
// May only be called AFTER this widget has been add()ed
assert(m_element != NULL);
IGUIListBox* irritem = getIrrlichtElement<IGUIListBox>();
CGUISTKListBox* irritem = getIrrlichtElement<CGUISTKListBox>();
if (blue)
{
@@ -402,3 +447,11 @@ EventPropagation ListWidget::transmitEvent(Widget* w,
return EVENT_LET;
}
// -----------------------------------------------------------------------------
int ListWidget::getItemID(const std::string internalName) const
{
const CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
assert(list != NULL);
return list->getRowByInternalName(internalName);
}

View File

@@ -22,10 +22,13 @@
#include <irrString.h>
#include "guiengine/widgets/CGUISTKListBox.h"
#include "guiengine/widget.hpp"
#include "guiengine/widgets/button_widget.hpp"
#include "utils/leak_check.hpp"
#include "utils/ptr_vector.hpp"
#include "IGUIElement.h"
namespace irr { namespace gui { class STKModifiedSpriteBank; } }
@@ -47,7 +50,6 @@ namespace GUIEngine
class ListWidget : public Widget
{
friend class Skin;
/** \brief whether this list has icons */
bool m_use_icons;
@@ -55,14 +57,6 @@ namespace GUIEngine
/** \brief if m_use_icons is true, this will contain the icon bank */
irr::gui::STKModifiedSpriteBank* m_icons;
struct ListItem
{
std::string m_internal_name;
irr::core::stringw m_label;
int m_current_id;
};
std::vector< ListItem > m_items;
PtrVector< ButtonWidget > m_header_elements;
ButtonWidget* m_selected_column;
@@ -92,8 +86,10 @@ namespace GUIEngine
std::vector< Column > m_header;
IListWidgetHeaderListener* m_listener;
public:
typedef irr::gui::CGUISTKListBox::ListItem ListItem;
typedef ListItem::ListCell ListCell;
LEAK_CHECK()
@@ -130,8 +126,13 @@ namespace GUIEngine
* \param icon ID of the icon within the icon bank. Only used if an icon bank was passed.
* \pre may only be called after the widget has been added to the screen with add()
*/
void addItem(const std::string& internal_name,
const irr::core::stringw &name, const int icon=-1);
void addItem( const std::string& internal_name,
const irr::core::stringw &name,
const int icon=-1,
bool center = false);
void addItem( const std::string& internal_name,
PtrVector<ListCell> * contents);
/**
* \brief erases all items in the list
@@ -157,7 +158,7 @@ namespace GUIEngine
*/
std::string getSelectionInternalName();
irr::core::stringw getSelectionLabel() const;
irr::core::stringw getSelectionLabel(const int cell = 0) const;
void selectItemWithLabel(const irr::core::stringw& name);
@@ -177,18 +178,24 @@ namespace GUIEngine
* \brief rename an item and/or change its icon based on its ID
* \pre may only be called after the widget has been added to the screen with add()
*/
void renameItem(const int itemID, const irr::core::stringw newName, const int icon=-1);
void renameCell(const int row_num, const int col_num, const irr::core::stringw newName, const int icon=-1);
/**
* renames first cell only
*/
void renameItem(const int row_num, const irr::core::stringw newName, const int icon=-1);
void renameItem(const std::string & internal_name, const irr::core::stringw newName, const int icon=-1);
/**
* \brief rename an item and/or change its icon based on its internal name
* \pre may only be called after the widget has been added to the screen with add()
*/
void renameItem(const std::string internalName, const irr::core::stringw newName,
void renameCell(const std::string internalName, const int col_num, const irr::core::stringw newName,
const int icon=-1)
{
const int id = getItemID(internalName);
assert(id != -1);
renameItem( id, newName, icon );
renameCell( id, col_num, newName, icon );
}
/**

View File

@@ -16,13 +16,24 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "guiengine/engine.hpp"
#include "guiengine/modaldialog.hpp"
#include "guiengine/widgets/rating_bar_widget.hpp"
#include "utils/string_utils.hpp"
#include <string.h>
#include <IGUIEnvironment.h>
#include <IGUIElement.h>
#include <IGUIButton.h>
#include <cmath>
#ifdef WIN32
// VS up to and including VS 2012 do not provide the normal round function
static inline float round(float val)
{
return floor(val + 0.5f);
}
#endif
#include <string.h>
using namespace GUIEngine;
using namespace irr::core;
@@ -31,16 +42,21 @@ using namespace irr;
// -----------------------------------------------------------------------------
RatingBarWidget::RatingBarWidget() : Widget(WTYPE_RATINGBAR)
{
m_rating = 0;
m_star_number = 0;
m_allow_voting = false;
m_rating = 0.0f;
m_hover_rating = 0.0f;
m_stars = 3;
m_steps = 3;
m_hovering = false;
for(int i = 0; i < m_stars; i++)
m_star_values.push_back(0);
}
// -----------------------------------------------------------------------------
void RatingBarWidget::add()
{
rect<s32> widget_size = rect<s32>(m_x, m_y, m_x + m_w, m_y + m_h);
const irr::core::recti widget_size = rect<s32>(m_x, m_y, m_x + m_w, m_y + m_h);
m_element = GUIEngine::getGUIEnv()->addButton(widget_size, m_parent, getNewNoFocusID(), NULL, L"");
m_id = m_element->getID();
m_element->setTabStop(false);
m_element->setTabGroup(false);
@@ -50,36 +66,65 @@ void RatingBarWidget::add()
/** Get the current step of the star
*
* \param index The index of the star.
* \param max_step The number of different steps that a star can display. Two
* step are obligatory: full and empty.
* \return The current step of the star.
*/
int RatingBarWidget::getStepOfStar(int index, int max_step)
int RatingBarWidget::getStepsOfStar(int index)
{
assert(index >= 0 && index < m_star_number); // Index must be between 0 and m_star_number - 1.
assert(max_step >= 2); // The maximun number of step must be superior or equals to 2.
assert(index >= 0 && index < m_stars); // Index must be between 0 and m_star_number - 1.
if (m_rating < index)
{
return 0;
}
else if (m_rating > index + 1)
{
return max_step - 1;
}
else
{
float step_size = 1 / (float)(max_step - 1);
for (int i = 0; i < max_step; i++)
{
if (m_rating > index + step_size * (i - 0.5)
&& m_rating < index + step_size * (i + 0.5))
return i;
}
}
return 0;
// TODO: Assert or throws a exception, what type?
return m_star_values[index];
} // getStepOfStar
void RatingBarWidget::setStepValues(float float_rating)
{
for (int star = 0; star < m_stars; star++)
{
if (float_rating < star)
m_star_values[star] = 0;
else if (float_rating > star + 1)
m_star_values[star] = m_steps-1;
else
{
m_star_values[star] =(int)round((float_rating * (m_steps-1)) - (star*(m_steps-1)));
}
}
}
// -----------------------------------------------------------------------------
void RatingBarWidget::setRating(float rating)
{
m_rating = rating;
setStepValues(m_rating);
}
// -----------------------------------------------------------------------------
void RatingBarWidget::setStepValuesByMouse(const core::position2di & mouse_position, const core::recti & stars_rect)
{
if(m_allow_voting){
if(stars_rect.isPointInside(mouse_position))
{
m_hovering = true;
float exact_hover = (float)(mouse_position.X - stars_rect.UpperLeftCorner.X) / (float)stars_rect.getWidth() * (float)m_stars;
m_hover_rating = round(exact_hover * (m_steps-1)) / (m_steps-1);
setStepValues(m_hover_rating);
}
else if(m_hovering)
{
setStepValues(m_rating);
m_hovering = false;
}
}
}
void RatingBarWidget::onClick()
{
if(m_allow_voting)
m_rating = m_hover_rating;
}

View File

@@ -1,5 +1,6 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009-2013 Marianne Gagnon
// 2013 Glenn De Jonghe
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -34,10 +35,17 @@ namespace GUIEngine
*/
class RatingBarWidget : public Widget
{
float m_rating;
int m_star_number;
private:
float m_rating;
float m_hover_rating;
int m_stars;
int m_steps;
std::vector<int> m_star_values;
bool m_hovering;
bool m_allow_voting;
void setStepValues(float rating);
public:
LEAK_CHECK()
@@ -45,21 +53,29 @@ namespace GUIEngine
RatingBarWidget();
virtual ~RatingBarWidget() {}
void add();
/** Change the rating value of the widget. */
void setRating(float rating) { m_rating = rating; };
void setRating(float rating);
/** Get the current value of the widget. */
float getRating() {return m_rating; };
/** Change the number of star of the widget. */
void setStarNumber(int star_number) { m_star_number = star_number; };
/** Change the number of stars of the widget. */
void setStarNumber(int star_number) { m_stars = star_number; };
/** Get the current number of star of the widget. */
int getStarNumber() {return m_star_number; };
/** Get the current number of stars of the widget. */
int getStarNumber() {return m_stars; };
int getStepOfStar(int index, int max_step);
int getStepsOfStar(int index);
void setStepValuesByMouse(const core::position2di & mouse_position, const core::recti & stars_rect);
virtual void onClick();
void allowVoting() { m_allow_voting = true; }
};
}

View File

@@ -61,6 +61,13 @@ RibbonWidget::RibbonWidget(const RibbonType type) : Widget(WTYPE_RIBBON)
updateSelection();
} // RibbonWidget
// ----------------------------------------------------------------------------
RibbonWidget::~RibbonWidget()
{
m_active_children.clearWithoutDeleting();
} // ~RibbonWidget
// ----------------------------------------------------------------------------
void RibbonWidget::add()
{
@@ -81,7 +88,15 @@ void RibbonWidget::add()
m_parent, id, L"");
m_element = btn;
const int subbuttons_amount = m_children.size();
m_active_children.clearWithoutDeleting(); // Is just a copy of m_children without the deactivated children. m_children takes care of memory.
for (int i=0; i<m_children.size(); i++)
{
if (m_children[i].isVisible())
{
m_active_children.push_back(m_children.get(i));
}
}
const int subbuttons_amount = m_active_children.size();
// For some ribbon types, we can have unequal sizes depending on whether
// items have labels or not
@@ -94,11 +109,11 @@ void RibbonWidget::add()
for (int i=0; i<subbuttons_amount; i++)
{
// FIXME: why do I manually invoke the Layout Manager here?
LayoutManager::readCoords(m_children.get(i));
LayoutManager::applyCoords(m_children.get(i), NULL, this);
LayoutManager::readCoords(m_active_children.get(i));
LayoutManager::applyCoords(m_active_children.get(i), NULL, this);
if (m_children[i].m_type != WTYPE_ICON_BUTTON &&
m_children[i].m_type != WTYPE_BUTTON)
if (m_active_children[i].m_type != WTYPE_ICON_BUTTON &&
m_active_children[i].m_type != WTYPE_BUTTON)
{
fprintf(stderr, "/!\\ Warning /!\\ : ribbon widgets can only have "
"(icon)button widgets as children\n");
@@ -107,15 +122,15 @@ void RibbonWidget::add()
// ribbon children must not be keyboard navigatable, the parent
// ribbon takes care of that
if (m_children[i].m_type == WTYPE_ICON_BUTTON)
if (m_active_children[i].m_type == WTYPE_ICON_BUTTON)
{
IconButtonWidget* icon = ((IconButtonWidget*)m_children.get(i));
IconButtonWidget* icon = ((IconButtonWidget*)m_active_children.get(i));
icon->m_tab_stop = false;
}
bool has_label_underneath = m_children[i].m_text.size() > 0;
if (m_children[i].m_properties[PROP_LABELS_LOCATION].size() > 0)
bool has_label_underneath = m_active_children[i].m_text.size() > 0;
if (m_active_children[i].m_properties[PROP_LABELS_LOCATION].size() > 0)
{
has_label_underneath = false;
}
@@ -123,7 +138,7 @@ void RibbonWidget::add()
if (has_label_underneath) with_label++;
else without_label++;
total_needed_space += m_children[i].m_w;
total_needed_space += m_active_children[i].m_w;
}
int free_w_space = m_w - total_needed_space;
@@ -152,7 +167,7 @@ void RibbonWidget::add()
/ (with_label + without_label/2.0f));
const int small_tab = large_tab/2;
stringw& message = m_children[i].m_text;
stringw& message = m_active_children[i].m_text;
if (message.size() == 0)
@@ -176,7 +191,7 @@ void RibbonWidget::add()
widget_x + small_tab/2-2, m_h);
}
if (m_children[i].m_type == WTYPE_BUTTON)
if (m_active_children[i].m_type == WTYPE_BUTTON)
{
subbtn = GUIEngine::getGUIEnv()
->addButton(subsize, btn, getNewNoFocusID(),
@@ -194,7 +209,7 @@ void RibbonWidget::add()
subbtn->setOverrideFont(GUIEngine::getSmallFont());
}
}
else if (m_children[i].m_type == WTYPE_ICON_BUTTON)
else if (m_active_children[i].m_type == WTYPE_ICON_BUTTON)
{
rect<s32> icon_part = rect<s32>(15,
0,
@@ -229,7 +244,7 @@ void RibbonWidget::add()
same_id, L"");
icon->setScaleImage(true);
std::string filename = file_manager->getDataDir()
+ m_children[i].m_properties[PROP_ICON];
+ m_active_children[i].m_properties[PROP_ICON];
icon->setImage( irr_driver->getTexture(filename.c_str()) );
icon->setUseAlphaChannel(true);
icon->setDrawBorder(false);
@@ -264,21 +279,21 @@ void RibbonWidget::add()
fprintf(stderr, "Invalid tab bar contents\n");
}
m_children[i].m_element = subbtn;
m_active_children[i].m_element = subbtn;
if (message.size() == 0) widget_x += small_tab/2;
else widget_x += large_tab/2;
}
// ---- icon ribbons
else if (m_children[i].m_type == WTYPE_ICON_BUTTON)
else if (m_active_children[i].m_type == WTYPE_ICON_BUTTON)
{
if (widget_x == -1) widget_x = one_button_space/2;
// find how much space to keep for the label under the button.
// consider font size, whether the label is multiline, etc...
bool has_label = m_children[i].m_text.size() > 0;
bool has_label = m_active_children[i].m_text.size() > 0;
if (m_children[i].m_properties[PROP_LABELS_LOCATION].size() > 0)
if (m_active_children[i].m_properties[PROP_LABELS_LOCATION].size() > 0)
{
has_label = false;
}
@@ -288,11 +303,11 @@ void RibbonWidget::add()
: 10;
float imageRatio =
(float)m_children[i].m_w / (float)m_children[i].m_h;
(float)m_active_children[i].m_w / (float)m_active_children[i].m_h;
// calculate the size of the image
std::string filename = file_manager->getDataDir()
+ m_children[i].m_properties[PROP_ICON];
+ m_active_children[i].m_properties[PROP_ICON];
video::ITexture* image =
irr_driver->getTexture((filename).c_str());
if(!image)
@@ -326,17 +341,17 @@ void RibbonWidget::add()
// ---- add bitmap button part
// backup and restore position in case the same object is added
// multiple times (FIXME: unclean)
int old_x = m_children[i].m_x;
int old_y = m_children[i].m_y;
int old_w = m_children[i].m_w;
int old_h = m_children[i].m_h;
int old_x = m_active_children[i].m_x;
int old_y = m_active_children[i].m_y;
int old_w = m_active_children[i].m_w;
int old_h = m_active_children[i].m_h;
m_children[i].m_x = widget_x - (int)(image_w*zoom/2.0f);
m_children[i].m_y = button_y;
m_children[i].m_w = (int)(image_w*zoom);
m_children[i].m_h = (int)(image_h*zoom);
m_active_children[i].m_x = widget_x - (int)(image_w*zoom/2.0f);
m_active_children[i].m_y = button_y;
m_active_children[i].m_w = (int)(image_w*zoom);
m_active_children[i].m_h = (int)(image_h*zoom);
IconButtonWidget* icon = ((IconButtonWidget*)m_children.get(i));
IconButtonWidget* icon = ((IconButtonWidget*)m_active_children.get(i));
if (icon->m_properties[PROP_EXTEND_LABEL].size() == 0)
{
@@ -344,14 +359,14 @@ void RibbonWidget::add()
StringUtils::toString(one_button_space - icon->m_w);
}
m_children.get(i)->m_parent = btn;
m_children.get(i)->add();
m_active_children.get(i)->m_parent = btn;
m_active_children.get(i)->add();
// restore backuped size and location (see above for more info)
m_children[i].m_x = old_x;
m_children[i].m_y = old_y;
m_children[i].m_w = old_w;
m_children[i].m_h = old_h;
m_active_children[i].m_x = old_x;
m_active_children[i].m_y = old_y;
m_active_children[i].m_w = old_w;
m_active_children[i].m_h = old_h;
// the label itself will be added by the icon widget. since it
// adds the label outside of the widget area it is assigned to,
@@ -367,7 +382,7 @@ void RibbonWidget::add()
//m_children[i].id = subbtn->getID();
m_children[i].m_event_handler = this;
m_active_children[i].m_event_handler = this;
}// next sub-button
id = m_element->getID();
@@ -445,11 +460,11 @@ void RibbonWidget::removeChildNamed(const char* name)
void RibbonWidget::select(std::string item, const int mousePlayerID)
{
const int subbuttons_amount = m_children.size();
const int subbuttons_amount = m_active_children.size();
for (int i=0; i<subbuttons_amount; i++)
{
if (m_children[i].m_properties[PROP_ID] == item)
if (m_active_children[i].m_properties[PROP_ID] == item)
{
m_selection[mousePlayerID] = i;
updateSelection();
@@ -464,15 +479,15 @@ EventPropagation RibbonWidget::rightPressed(const int playerID)
{
if (m_deactivated) return EVENT_LET;
// empty ribbon, or only one item (can't move right)
if (m_children.size() < 2) return EVENT_LET;
if (m_active_children.size() < 2) return EVENT_LET;
m_selection[playerID]++;
if (m_selection[playerID] >= m_children.size())
if (m_selection[playerID] >= m_active_children.size())
{
if (m_listener != NULL) m_listener->onRibbonWidgetScroll(1);
m_selection[playerID] = m_event_handler ? m_children.size()-1 : 0;
m_selection[playerID] = m_event_handler ? m_active_children.size()-1 : 0;
}
updateSelection();
@@ -481,14 +496,14 @@ EventPropagation RibbonWidget::rightPressed(const int playerID)
const int mousePlayerID = input_manager->getPlayerKeyboardID();
if (playerID == mousePlayerID || playerID == PLAYER_ID_GAME_MASTER)
{
m_mouse_focus = m_children.get(m_selection[playerID]);
m_mouse_focus = m_active_children.get(m_selection[playerID]);
}
}
// if we reached a filler item, move again (but don't wrap)
if (getSelectionIDString(playerID) == RibbonWidget::NO_ITEM_ID)
{
if (m_selection[playerID] + 1 < m_children.size())
if (m_selection[playerID] + 1 < m_active_children.size())
{
rightPressed(playerID);
}
@@ -502,7 +517,7 @@ EventPropagation RibbonWidget::leftPressed(const int playerID)
{
if (m_deactivated) return EVENT_LET;
// empty ribbon, or only one item (can't move left)
if (m_children.size() < 2) return EVENT_LET;
if (m_active_children.size() < 2) return EVENT_LET;
m_selection[playerID]--;
if (m_selection[playerID] < 0)
@@ -511,7 +526,7 @@ EventPropagation RibbonWidget::leftPressed(const int playerID)
m_selection[playerID] = m_event_handler
? 0
: m_children.size()-1;
: m_active_children.size()-1;
}
updateSelection();
@@ -521,7 +536,7 @@ EventPropagation RibbonWidget::leftPressed(const int playerID)
const int mousePlayerID = input_manager->getPlayerKeyboardID();
if (playerID == mousePlayerID || playerID == PLAYER_ID_GAME_MASTER)
{
m_mouse_focus = m_children.get(m_selection[playerID]);
m_mouse_focus = m_active_children.get(m_selection[playerID]);
}
}
@@ -548,7 +563,7 @@ EventPropagation RibbonWidget::focused(const int playerID)
{
Widget::focused(playerID);
if (m_children.size() < 1) return EVENT_LET; // empty ribbon
if (m_active_children.size() < 1) return EVENT_LET; // empty ribbon
if (m_ribbon_type == RIBBON_COMBO || m_ribbon_type == RIBBON_TABS)
{
@@ -556,7 +571,7 @@ EventPropagation RibbonWidget::focused(const int playerID)
if (m_mouse_focus == NULL && m_selection[playerID] != -1 &&
(playerID == mousePlayerID || playerID == PLAYER_ID_GAME_MASTER))
{
m_mouse_focus = m_children.get(m_selection[playerID]);
m_mouse_focus = m_active_children.get(m_selection[playerID]);
m_mouse_focus->focused(playerID);
}
}
@@ -564,7 +579,7 @@ EventPropagation RibbonWidget::focused(const int playerID)
{
if (m_selection[playerID] != -1)
{
m_children.get(m_selection[playerID])->focused(playerID);
m_active_children.get(m_selection[playerID])->focused(playerID);
}
}
@@ -578,11 +593,11 @@ EventPropagation RibbonWidget::focused(const int playerID)
void RibbonWidget::unfocused(const int playerID, Widget* new_focus)
{
if (new_focus != NULL && new_focus != this && !m_children.contains(new_focus))
if (new_focus != NULL && new_focus != this && !m_active_children.contains(new_focus))
{
if (m_selection[playerID] >= 0 && m_selection[playerID] < m_children.size())
{
m_children.get(m_selection[playerID])->unfocused(playerID, new_focus);
m_active_children.get(m_selection[playerID])->unfocused(playerID, new_focus);
}
}
@@ -595,7 +610,7 @@ EventPropagation RibbonWidget::mouseHovered(Widget* child,
{
if (m_deactivated) return EVENT_LET;
const int subbuttons_amount = m_children.size();
const int subbuttons_amount = m_active_children.size();
if (m_ribbon_type == RIBBON_COMBO || m_ribbon_type == RIBBON_TABS)
{
@@ -608,7 +623,7 @@ EventPropagation RibbonWidget::mouseHovered(Widget* child,
{
for (int i=0; i<subbuttons_amount; i++)
{
if (m_children.get(i) == child)
if (m_active_children.get(i) == child)
{
// Was already selected, don't send another event
if (m_selection[mousePlayerID] == i) return EVENT_BLOCK;
@@ -629,21 +644,21 @@ const std::string& RibbonWidget::getSelectionIDString(const int playerID)
{
static std::string empty;
if (m_selection[playerID] == -1) return empty;
if (m_children.size() == 0) return empty;
if (m_active_children.size() == 0) return empty;
// This can happen if an addon is removed, which causes a tab group
// to be removed. If this tab group was previously selected, an
// invalid array element would be accessed. In this case just pretend
// that the first child was selected previously.
if(m_selection[playerID]>=m_children.size())
return m_children[0].m_properties[PROP_ID];
return m_children[m_selection[playerID]].m_properties[PROP_ID];
if(m_selection[playerID]>=m_active_children.size())
return m_active_children[0].m_properties[PROP_ID];
return m_active_children[m_selection[playerID]].m_properties[PROP_ID];
} // getSelectionIDString
// ----------------------------------------------------------------------------
void RibbonWidget::updateSelection()
{
const int subbuttons_amount = m_children.size();
const int subbuttons_amount = m_active_children.size();
// FIXME: m_selection, m_selected, m_mouse_focus... what a mess...
@@ -654,12 +669,12 @@ void RibbonWidget::updateSelection()
for (int i=0; i<subbuttons_amount; i++)
{
bool new_val = (i == m_selection[p]);
if (!new_val && m_children[i].m_selected[p])
if (!new_val && m_active_children[i].m_selected[p])
{
m_children[i].unfocused(PLAYER_ID_GAME_MASTER, NULL);
m_active_children[i].unfocused(PLAYER_ID_GAME_MASTER, NULL);
}
m_children[i].m_selected[p] = new_val;
if (new_val) m_children[i].focused(PLAYER_ID_GAME_MASTER);
m_active_children[i].m_selected[p] = new_val;
if (new_val) m_active_children[i].focused(PLAYER_ID_GAME_MASTER);
}
}
@@ -676,11 +691,11 @@ EventPropagation RibbonWidget::transmitEvent(Widget* w,
if (!m_deactivated)
{
const int subbuttons_amount = m_children.size();
const int subbuttons_amount = m_active_children.size();
for (int i=0; i<subbuttons_amount; i++)
{
if (m_children[i].m_properties[PROP_ID] == originator)
if (m_active_children[i].m_properties[PROP_ID] == originator)
{
m_selection[playerID] = i;
break;
@@ -695,10 +710,10 @@ EventPropagation RibbonWidget::transmitEvent(Widget* w,
if (m_selection[playerID] != -1)
{
if (m_children[m_selection[playerID]].m_deactivated)
if (m_active_children[m_selection[playerID]].m_deactivated)
{
GUIEngine::getCurrentScreen()->onDisabledItemClicked(
m_children[m_selection[playerID]].m_properties[PROP_ID]);
m_active_children[m_selection[playerID]].m_properties[PROP_ID]);
return EVENT_BLOCK;
}
@@ -737,3 +752,12 @@ int RibbonWidget::findItemNamed(const char* internalName)
}
return -1;
} // findItemNamed
// ----------------------------------------------------------------------------
Widget* RibbonWidget::findWidgetNamed(const char* internalName)
{
int id = findItemNamed(internalName);
if (id >= 0)
return m_children.get(id);
return NULL;
} // findItemNamed

View File

@@ -87,7 +87,7 @@ namespace GUIEngine
PtrVector<irr::gui::IGUIStaticText, REF> m_labels;
IRibbonListener* m_listener;
PtrVector<Widget> m_active_children;
public:
@@ -106,7 +106,7 @@ namespace GUIEngine
Widget* m_mouse_focus;
RibbonWidget(const RibbonType type=RIBBON_COMBO);
virtual ~RibbonWidget() {}
virtual ~RibbonWidget();
void add();
@@ -155,6 +155,9 @@ namespace GUIEngine
/** Returns the ID of the item, or -1 if not found */
int findItemNamed(const char* internalName);
/** Returns the the widget, or NULL if not found */
GUIEngine::Widget * findWidgetNamed(const char* interalName);
/** \brief Dynamically (at runtime) add a text item to this ribbon
* \pre This must be called before RibbonWidget::add, while the
* widget is not yet displayed

View File

@@ -128,6 +128,15 @@ stringw TextBoxWidget::getText() const
// -----------------------------------------------------------------------------
void TextBoxWidget::setPasswordBox(bool passwordBox, wchar_t passwordChar)
{
IGUIEditBox* textCtrl = Widget::getIrrlichtElement<IGUIEditBox>();
assert(textCtrl != NULL);
textCtrl->setPasswordBox(passwordBox, passwordChar);
}
// -----------------------------------------------------------------------------
EventPropagation TextBoxWidget::focused(const int playerID)
{
assert(playerID == 0); // No support for multiple players in text areas!

View File

@@ -68,6 +68,7 @@ namespace GUIEngine
void clearListeners();
irr::core::stringw getText() const;
void setPasswordBox(bool passwordBox, wchar_t passwordChar = L'*');
virtual void elementRemoved();
};

View File

@@ -595,7 +595,7 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID,
action == PA_MENU_CANCEL ) )
{
// returns true if the event was handled
if (KartSelectionScreen::getInstance()->playerQuit( player ))
if (KartSelectionScreen::getRunningInstance()->playerQuit( player ))
{
return; // we're done here
}
@@ -630,7 +630,7 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID,
if (device != NULL)
{
KartSelectionScreen::getInstance()->playerJoin(device,
KartSelectionScreen::getRunningInstance()->playerJoin(device,
false );
}
}

View File

@@ -293,7 +293,33 @@ XMLNode *FileManager::createXMLTree(const std::string &filename)
}
return NULL;
}
} // getXMLTree
} // createXMLTree
//-----------------------------------------------------------------------------
/** Reads in XML from a string and converts it into a XMLNode tree.
* \param content the string containing the XML content.
*/
XMLNode *FileManager::createXMLTreeFromString(const std::string & content)
{
try
{
char *b = new char[content.size()];
memcpy(b, content.c_str(), content.size());
io::IReadFile * ireadfile = m_file_system->createMemoryReadFile(b, strlen(b), "tempfile", true);
io::IXMLReader * reader = m_file_system->createXMLReader(ireadfile);
XMLNode* node = new XMLNode(reader);
reader->drop();
return node;
}
catch (std::runtime_error& e)
{
if (UserConfigParams::logMisc())
{
Log::error("FileManager", "createXMLTreeFromString: %s\n", e.what());
}
return NULL;
}
} // createXMLTreeFromString
//-----------------------------------------------------------------------------
/** In order to add and later remove paths we have to specify the absolute
@@ -818,7 +844,7 @@ std::string FileManager::checkAndCreateLinuxDir(const char *env_name,
void FileManager::redirectOutput()
{
//Enable logging of stdout and stderr to logfile
std::string logoutfile = getLogFile("stdout.log");
std::string logoutfile = getConfigFile("stdout.log");
Log::verbose("main", "Error messages and other text output will "
"be logged to %s.", logoutfile.c_str());
Log::openOutputFiles(logoutfile);
@@ -848,16 +874,6 @@ std::string FileManager::getConfigDir() const
return m_config_dir;
} // getConfigDir
//-----------------------------------------------------------------------------
/** Returns the full path of a file in the user config directory which is
* used to store stdout/stderr if it is redirected.
* \param name Name of the file.
*/
std::string FileManager::getLogFile(const std::string& file_name) const
{
return getConfigDir()+"/"+file_name;
} // getLogFile
//-----------------------------------------------------------------------------
/** Returns the full path of a music file by searching all music search paths.
* It throws an exception if the file is not found.
@@ -895,33 +911,14 @@ std::string FileManager::getFontFile(const std::string& file_name) const
} // getFontFile
//-----------------------------------------------------------------------------
/** Returns the full path of a highscore file (which is stored in the user
* specific config directory).
* \param file_name Name of the sound effect file.
*/
std::string FileManager::getHighscoreFile(const std::string& file_name) const
{
return getConfigDir()+"/"+file_name;
} // getHighscoreFile
//-----------------------------------------------------------------------------
/** Returns the full path of the challenge file (which is stored in a user
* specific config area).
/** Returns the full path of a file in the config dir
* \param file_name Name of the file.
*/
std::string FileManager::getChallengeFile(const std::string &file_name) const
std::string FileManager::getConfigFile(const std::string &file_name) const
{
return getConfigDir()+"/"+file_name;
return getConfigDir()+file_name;
} // getChallengeFile
//-----------------------------------------------------------------------------
/** Returns the full path of the tutorial file.
* \param file_name Name of the tutorial file to return.
*/
std::string FileManager::getTutorialFile(const std::string &file_name) const
{
return getConfigDir()+"/"+file_name;
} // getTutorialFile
//-----------------------------------------------------------------------------
/** Returns true if the given name is a directory.

View File

@@ -89,6 +89,7 @@ public:
void dropFileSystem();
io::IXMLReader *createXMLReader(const std::string &filename);
XMLNode *createXMLTree(const std::string &filename);
XMLNode *createXMLTreeFromString(const std::string & content);
std::string getConfigDir() const;
std::string getTextureDir() const;
@@ -106,10 +107,7 @@ public:
std::vector<std::string>getMusicDirs() const;
std::string getTextureFile (const std::string& fname) const;
std::string getDataFile (const std::string& fname) const;
std::string getHighscoreFile (const std::string& fname) const;
std::string getChallengeFile (const std::string& fname) const;
std::string getTutorialFile (const std::string& fname) const;
std::string getLogFile (const std::string& fname) const;
std::string getConfigFile (const std::string& fname) const;
std::string getItemFile (const std::string& fname) const;
std::string getGfxFile (const std::string& fname) const;
std::string getMusicFile (const std::string& fname) const;

View File

@@ -41,7 +41,7 @@ XMLNode::XMLNode(const std::string &filename)
m_file_name = filename;
io::IXMLReader *xml = file_manager->createXMLReader(filename);
if (xml == NULL)
{
throw std::runtime_error("Cannot find file "+filename);
@@ -319,6 +319,22 @@ int XMLNode::get(const std::string &attribute, int64_t *value) const
} // get(int64_t)
// ----------------------------------------------------------------------------
int XMLNode::get(const std::string &attribute, uint16_t *value) const
{
std::string s;
if(!get(attribute, &s)) return 0;
if (!StringUtils::parseString<uint16_t>(s, value))
{
fprintf(stderr, "[XMLNode] WARNING: Expected uint but found '%s' for attribute '%s' of node '%s' in file %s\n",
s.c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str());
return 0;
}
return 1;
} // get(uint32_t)
// ----------------------------------------------------------------------------
int XMLNode::get(const std::string &attribute, uint32_t *value) const
{

View File

@@ -19,15 +19,6 @@
#ifndef HEADER_XML_NODE_HPP
#define HEADER_XML_NODE_HPP
#ifdef _MSC_VER
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
# include <stdint.h>
#endif
#include <string>
#include <map>
#include <vector>
@@ -43,6 +34,7 @@ using namespace irr;
#include "utils/leak_check.hpp"
#include "utils/no_copy.hpp"
#include "utils/time.hpp"
#include "utils/types.hpp"
class InterpolationArray;
class Vec3;
@@ -82,6 +74,7 @@ public:
int get(const std::string &attribute, std::string *value) const;
int get(const std::string &attribute, core::stringw *value) const;
int get(const std::string &attribute, int32_t *value) const;
int get(const std::string &attribute, uint16_t *value) const;
int get(const std::string &attribute, uint32_t *value) const;
int get(const std::string &attribute, int64_t *value) const;
int get(const std::string &attribute, float *value) const;

View File

@@ -34,8 +34,8 @@
#include "karts/kart_properties.hpp"
#include "modes/three_strikes_battle.hpp"
#include "modes/world.hpp"
#include "network/race_state.hpp"
#include "network/network_manager.hpp"
#include "physics/triangle_mesh.hpp"
#include "tracks/track.hpp"
#include "physics/triangle_mesh.hpp"
#include "tracks/track.hpp"
#include "utils/constants.hpp"
@@ -283,15 +283,6 @@ void Attachment::hitBanana(Item *item, int new_attachment)
new_attachment = m_random.get(3);
} // switch
// Save the information about the attachment in the race state
// so that the clients can be updated.
if(network_manager->getMode()==NetworkManager::NW_SERVER)
{
race_state->itemCollected(m_kart->getWorldKartId(),
item->getItemId(),
new_attachment);
}
if (add_a_new_item)
{
switch (new_attachment)

View File

@@ -35,7 +35,6 @@
#include "karts/abstract_kart.hpp"
#include "karts/explosion_animation.hpp"
#include "modes/world.hpp"
#include "network/flyable_info.hpp"
#include "physics/physics.hpp"
#include "tracks/track.hpp"
#include "utils/constants.hpp"
@@ -409,19 +408,6 @@ bool Flyable::updateAndDelete(float dt)
return false;
} // updateAndDelete
// ----------------------------------------------------------------------------
/** Updates the position of a projectile based on information received frmo the
* server.
*/
void Flyable::updateFromServer(const FlyableInfo &f, float dt)
{
setXYZ(f.m_xyz);
setRotation(f.m_rotation);
// Update the graphical position
Moveable::update(dt);
} // updateFromServer
// ----------------------------------------------------------------------------
/** Returns true if the item hit the kart who shot it (to avoid that an item
* that's too close to the shooter hits the shooter).

View File

@@ -34,7 +34,6 @@ using namespace irr;
#include "tracks/terrain_info.hpp"
class AbstractKart;
class FlyableInfo;
class HitEffect;
class PhysicalObject;
class XMLNode;
@@ -168,7 +167,6 @@ public:
PowerupManager::PowerupType type);
virtual bool updateAndDelete(float);
virtual HitEffect* getHitEffect() const;
void updateFromServer(const FlyableInfo &f, float dt);
bool isOwnerImmunity(const AbstractKart *kart_hit) const;
virtual bool hit(AbstractKart* kart, PhysicalObject* obj=NULL);
void explode(AbstractKart* kart, PhysicalObject* obj=NULL,

View File

@@ -29,7 +29,6 @@
#include "io/file_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "modes/linear_world.hpp"
#include "network/network_manager.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/track.hpp"
#include "utils/string_utils.hpp"
@@ -293,9 +292,6 @@ void ItemManager::collectedItem(Item *item, AbstractKart *kart, int add_info)
*/
void ItemManager::checkItemHit(AbstractKart* kart)
{
// Only do this on the server
if(network_manager->getMode()==NetworkManager::NW_CLIENT) return;
// We could use m_items_in_quads to to check for item hits: take the quad
// of the graph node of the kart, and only check items in that quad. But
// then we also need to check for any adjacent quads (since an item just

View File

@@ -29,8 +29,6 @@
#include "karts/controller/controller.hpp"
#include "karts/kart_properties.hpp"
#include "modes/world.hpp"
#include "network/network_manager.hpp"
#include "network/race_state.hpp"
#include "physics/triangle_mesh.hpp"
#include "tracks/track.hpp"
#include "utils/string_utils.hpp"
@@ -188,7 +186,6 @@ void Powerup::use()
m_number--;
World *world = World::getWorld();
RaceGUIBase* gui = world->getRaceGUI();
switch (m_type)
{
case PowerupManager::POWERUP_ZIPPER:

View File

@@ -26,8 +26,7 @@
#include "items/powerup_manager.hpp"
#include "items/powerup.hpp"
#include "items/rubber_ball.hpp"
#include "network/network_manager.hpp"
#include "network/race_state.hpp"
#include "karts/abstract_kart.hpp"
ProjectileManager *projectile_manager=0;
@@ -66,14 +65,7 @@ void ProjectileManager::cleanup()
/** General projectile update call. */
void ProjectileManager::update(float dt)
{
if(network_manager->getMode()==NetworkManager::NW_CLIENT)
{
updateClient(dt);
}
else
{
updateServer(dt);
}
updateServer(dt);
HitEffects::iterator he = m_active_hit_effects.begin();
while(he!=m_active_hit_effects.end())
@@ -100,23 +92,10 @@ void ProjectileManager::update(float dt)
/** Updates all rockets on the server (or no networking). */
void ProjectileManager::updateServer(float dt)
{
// First update all projectiles on the track
if(network_manager->getMode()!=NetworkManager::NW_NONE)
{
race_state->setNumFlyables(m_active_projectiles.size());
}
Projectiles::iterator p = m_active_projectiles.begin();
while(p!=m_active_projectiles.end())
{
bool can_be_deleted = (*p)->updateAndDelete(dt);
if(network_manager->getMode()!=NetworkManager::NW_NONE)
{
race_state->setFlyableInfo(p-m_active_projectiles.begin(),
FlyableInfo((*p)->getXYZ(),
(*p)->getRotation(),
can_be_deleted) );
}
if(can_be_deleted)
{
HitEffect *he = (*p)->getHitEffect();
@@ -130,33 +109,9 @@ void ProjectileManager::updateServer(float dt)
else
p++;
} // while p!=m_active_projectiles.end()
} // updateServer
// -----------------------------------------------------------------------------
/** Updates all rockets and hit effects on the client.
* updateClient takes the information in race_state and updates all rockets
* (i.e. position, hit effects etc) */
void ProjectileManager::updateClient(float dt)
{
unsigned int num_projectiles = race_state->getNumFlyables();
if(num_projectiles != m_active_projectiles.size())
fprintf(stderr, "Warning: num_projectiles %d active %d\n",
num_projectiles, (int)m_active_projectiles.size());
unsigned int indx=0;
for(Projectiles::iterator i = m_active_projectiles.begin();
i != m_active_projectiles.end(); ++i, ++indx)
{
const FlyableInfo &f = race_state->getFlyable(indx);
(*i)->updateFromServer(f, dt);
if(f.m_exploded)
{
(*i)->hit(NULL);
}
} // for i in m_active_projectiles
} // updateClient
// -----------------------------------------------------------------------------
/** Creates a new projectile of the given type.
* \param kart The kart which shoots the projectile.
@@ -178,6 +133,7 @@ Flyable *ProjectileManager::newProjectile(AbstractKart *kart,
m_active_projectiles.push_back(f);
return f;
} // newProjectile
// -----------------------------------------------------------------------------
/** Returns true if a projectile is within the given distance of the specified
* kart.

View File

@@ -53,7 +53,6 @@ private:
* being shown or have a sfx playing. */
HitEffects m_active_hit_effects;
void updateClient(float dt);
void updateServer(float dt);
public:
ProjectileManager() {}

View File

@@ -37,7 +37,7 @@ class Item;
class KartControl;
class Material;
/** This is the base class for kart controller - that can be a player
/** This is the base class for kart controller - that can be a player
* or a a robot.
* \ingroup controller
*/
@@ -58,7 +58,7 @@ protected:
/** The name of the controller, mainly used for debugging purposes. */
std::string m_controller_name;
public:
Controller (AbstractKart *kart,
Controller (AbstractKart *kart,
StateManager::ActivePlayer *player=NULL);
virtual ~Controller () {};
virtual void reset () = 0;
@@ -74,20 +74,20 @@ public:
virtual bool disableSlipstreamBonus() const = 0;
// ---------------------------------------------------------------------------
/** Sets the controller name for this controller. */
virtual void setControllerName(const std::string &name)
virtual void setControllerName(const std::string &name)
{ m_controller_name = name; }
// ---------------------------------------------------------------------------
/** Returns the name of this controller. */
const std::string &getControllerName() const { return m_controller_name; }
// ---------------------------------------------------------------------------
/** Returns the active player for this controller (NULL
/** Returns the active player for this controller (NULL
* if this controller does not belong to a player. */
StateManager::ActivePlayer *getPlayer () {return m_player;}
// ---------------------------------------------------------------------------
/** Returns the player object (or NULL if it's a computer controller). */
const StateManager::ActivePlayer *getPlayer () const { return m_player; }
// ------------------------------------------------------------------------
/** Default: ignore actions. Only PlayerController get them. */
virtual void action(PlayerAction action, int value) = 0;
@@ -101,6 +101,9 @@ public:
/** Called whan this controller's kart finishes the last lap. */
virtual void finishedRace(float time) = 0;
// ------------------------------------------------------------------------
/** Get a pointer on the kart controls. */
virtual KartControl* getControls() { return m_controls; }
// ------------------------------------------------------------------------
}; // Controller
#endif

View File

@@ -43,7 +43,6 @@
#include "karts/max_speed.hpp"
#include "karts/rescue_animation.hpp"
#include "modes/linear_world.hpp"
#include "network/network_manager.hpp"
#include "race/race_manager.hpp"
#include "states_screens/race_result_gui.hpp"
#include "tracks/quad_graph.hpp"

View File

@@ -19,9 +19,8 @@
#ifndef HEADER_KART_CONTROL_HPP
#define HEADER_KART_CONTROL_HPP
#include "network/message.hpp"
/**
/**
* \ingroup controller
*/
class KartControl
@@ -52,15 +51,6 @@ public:
reset();
}
// ------------------------------------------------------------------------
/** Construct kart control from a Message (i.e. unserialise) */
KartControl(Message *m)
{
m_steer = m->getFloat();
m_accel = m->getFloat();
char c = m->getChar();
setButtonsCompressed(c);
} // KartControl(Message*)
// ------------------------------------------------------------------------
/** Resets all controls. */
void reset()
{
@@ -74,17 +64,6 @@ public:
m_look_back = false;
} // reset
// ------------------------------------------------------------------------
/** Return the serialised size in bytes. */
static int getLength() { return 9; }
// ------------------------------------------------------------------------
/** Serialises the kart control into a message. */
void serialise(Message *m) const
{
m->addFloat(m_steer);
m->addFloat(m_accel);
m->addChar(getButtonsCompressed());
} // compress
// ------------------------------------------------------------------------
void uncompress(char *c)
{
m_steer = ((float*)c)[0];

View File

@@ -0,0 +1,368 @@
#include "karts/controller/network_player_controller.hpp"
#include "config/player.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/post_processing.hpp"
#include "input/input_manager.hpp"
#include "items/attachment.hpp"
#include "items/item.hpp"
#include "items/powerup.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/kart_properties.hpp"
#include "karts/skidding.hpp"
#include "karts/rescue_animation.hpp"
#include "modes/world.hpp"
#include "race/history.hpp"
#include "states_screens/race_gui_base.hpp"
#include "utils/constants.hpp"
#include "utils/log.hpp"
#include "utils/translation.hpp"
NetworkPlayerController::NetworkPlayerController(AbstractKart *kart,
StateManager::ActivePlayer *player)
: Controller(kart)
{
assert(player != NULL);
m_player = player;
m_player->setKart(kart);
m_penalty_time = 0.0f;
reset();
Log::info("NetworkPlayerController", "New network player controller.");
} // NetworkPlayerController
//-----------------------------------------------------------------------------
/** Destructor for a player kart.
*/
NetworkPlayerController::~NetworkPlayerController()
{
} // ~NetworkPlayerController
//-----------------------------------------------------------------------------
/** Resets the player kart for a new or restarted race.
*/
void NetworkPlayerController::reset()
{
m_steer_val_l = 0;
m_steer_val_r = 0;
m_steer_val = 0;
m_prev_brake = 0;
m_prev_accel = 0;
m_prev_nitro = false;
m_penalty_time = 0;
} // reset
// ----------------------------------------------------------------------------
/** Resets the state of control keys. This is used after the in-game menu to
* avoid that any keys pressed at the time the menu is opened are still
* considered to be pressed.
*/
void NetworkPlayerController::resetInputState()
{
m_steer_val_l = 0;
m_steer_val_r = 0;
m_steer_val = 0;
m_prev_brake = 0;
m_prev_accel = 0;
m_prev_nitro = false;
m_controls->reset();
} // resetInputState
// ----------------------------------------------------------------------------
/** This function interprets a kart action and value, and set the corresponding
* entries in the kart control data structure. This function handles esp.
* cases like 'press left, press right, release right' - in this case after
* releasing right, the steering must switch to left again. Similarly it
* handles 'press left, press right, release left' (in which case still
* right must be selected). Similarly for braking and acceleration.
* \param action The action to be executed.
* \param value If 32768, it indicates a digital value of 'fully set'
* if between 1 and 32767, it indicates an analog value,
* and if it's 0 it indicates that the corresponding button
* was released.
*/
void NetworkPlayerController::action(PlayerAction action, int value)
{
switch (action)
{
case PA_STEER_LEFT:
m_steer_val_l = value;
if (value)
{
m_steer_val = value;
if(m_controls->m_skid==KartControl::SC_NO_DIRECTION)
m_controls->m_skid = KartControl::SC_LEFT;
}
else
m_steer_val = m_steer_val_r;
break;
case PA_STEER_RIGHT:
m_steer_val_r = -value;
if (value)
{
m_steer_val = -value;
if(m_controls->m_skid==KartControl::SC_NO_DIRECTION)
m_controls->m_skid = KartControl::SC_RIGHT;
}
else
m_steer_val = m_steer_val_l;
break;
case PA_ACCEL:
m_prev_accel = value;
if (value && !(m_penalty_time > 0.0f))
{
m_controls->m_accel = value/32768.0f;
m_controls->m_brake = false;
m_controls->m_nitro = m_prev_nitro;
}
else
{
m_controls->m_accel = 0.0f;
m_controls->m_brake = m_prev_brake;
m_controls->m_nitro = false;
}
break;
case PA_BRAKE:
m_prev_brake = value!=0;
// let's consider below that to be a deadzone
if(value > 32768/2)
{
m_controls->m_brake = true;
m_controls->m_accel = 0.0f;
m_controls->m_nitro = false;
}
else
{
m_controls->m_brake = false;
m_controls->m_accel = m_prev_accel/32768.0f;
// Nitro still depends on whether we're accelerating
m_controls->m_nitro = (m_prev_nitro && m_prev_accel);
}
break;
case PA_NITRO:
// This basically keeps track whether the button still is being pressed
m_prev_nitro = (value != 0);
// Enable nitro only when also accelerating
m_controls->m_nitro = ((value!=0) && m_controls->m_accel);
break;
case PA_RESCUE:
m_controls->m_rescue = (value!=0);
break;
case PA_FIRE:
{
m_controls->m_fire = (value!=0);
break;
}
case PA_LOOK_BACK:
m_controls->m_look_back = (value!=0);
break;
case PA_DRIFT:
if(value==0)
m_controls->m_skid = KartControl::SC_NONE;
else
if(m_steer_val==0)
m_controls->m_skid = KartControl::SC_NO_DIRECTION;
else
m_controls->m_skid = m_steer_val<0
? KartControl::SC_RIGHT
: KartControl::SC_LEFT;
break;
case PA_PAUSE_RACE:
if (value != 0) StateManager::get()->escapePressed();
break;
default:
break;
}
} // action
//-----------------------------------------------------------------------------
/** Handles steering for a player kart.
*/
void NetworkPlayerController::steer(float dt, int steer_val)
{
if(stk_config->m_disable_steer_while_unskid &&
m_controls->m_skid==KartControl::SC_NONE &&
m_kart->getSkidding()->getVisualSkidRotation()!=0)
{
m_controls->m_steer = 0;
}
// Amount the steering is changed for digital devices.
// If the steering is 'back to straight', a different steering
// change speed is used.
const float STEER_CHANGE = ( (steer_val<=0 && m_controls->m_steer<0) ||
(steer_val>=0 && m_controls->m_steer>0) )
? dt/m_kart->getKartProperties()->getTimeResetSteer()
: dt/m_kart->getTimeFullSteer(fabsf(m_controls->m_steer));
if (steer_val < 0)
{
// If we got analog values do not cumulate.
if (steer_val > -32767)
m_controls->m_steer = -steer_val/32767.0f;
else
m_controls->m_steer += STEER_CHANGE;
}
else if(steer_val > 0)
{
// If we got analog values do not cumulate.
if (steer_val < 32767)
m_controls->m_steer = -steer_val/32767.0f;
else
m_controls->m_steer -= STEER_CHANGE;
}
else
{ // no key is pressed
if(m_controls->m_steer>0.0f)
{
m_controls->m_steer -= STEER_CHANGE;
if(m_controls->m_steer<0.0f) m_controls->m_steer=0.0f;
}
else
{ // m_controls->m_steer<=0.0f;
m_controls->m_steer += STEER_CHANGE;
if(m_controls->m_steer>0.0f) m_controls->m_steer=0.0f;
} // if m_controls->m_steer<=0.0f
} // no key is pressed
if(UserConfigParams::m_gamepad_debug)
{
Log::debug("PlayerController", " set to: %f\n", m_controls->m_steer);
}
m_controls->m_steer = std::min(1.0f, std::max(-1.0f, m_controls->m_steer));
} // steer
//-----------------------------------------------------------------------------
/** Callback when the skidding bonus is triggered. The player controller
* resets the current steering to 0, which makes the kart easier to control.
*/
void NetworkPlayerController::skidBonusTriggered()
{
m_controls->m_steer = 0;
} // skidBonusTriggered
//-----------------------------------------------------------------------------
/** Updates the player kart, called once each timestep.
*/
void NetworkPlayerController::update(float dt)
{
if (UserConfigParams::m_gamepad_debug)
{
// Print a dividing line so that it's easier to see which events
// get received in which order in the one frame.
Log::debug("PlayerController", "irr_driver", "-------------------------------------\n");
}
// Don't do steering if it's replay. In position only replay it doesn't
// matter, but if it's physics replay the gradual steering causes
// incorrect results, since the stored values are already adjusted.
if (!history->replayHistory())
steer(dt, m_steer_val);
if (World::getWorld()->isStartPhase())
{
if (m_controls->m_accel || m_controls->m_brake ||
m_controls->m_fire || m_controls->m_nitro)
{
// Only give penalty time in SET_PHASE.
// Penalty time check makes sure it doesn't get rendered on every
// update.
if (m_penalty_time == 0.0 &&
World::getWorld()->getPhase() == WorldStatus::SET_PHASE)
{
RaceGUIBase* m=World::getWorld()->getRaceGUI();
if (m)
{
m->addMessage(_("Penalty time!!"), m_kart, 2.0f,
video::SColor(255, 255, 128, 0));
m->addMessage(_("Don't accelerate before go"), m_kart, 2.0f,
video::SColor(255, 210, 100, 50));
}
m_penalty_time = stk_config->m_penalty_time;
} // if penalty_time = 0
m_controls->m_brake = false;
m_controls->m_accel = 0.0f;
} // if key pressed
return;
} // if isStartPhase
if (m_penalty_time>0.0)
{
m_penalty_time-=dt;
return;
}
// We can't restrict rescue to fulfil isOnGround() (which would be more like
// MK), since e.g. in the City track it is possible for the kart to end
// up sitting on a brick wall, with all wheels in the air :((
// Only accept rescue if there is no kart animation is already playing
// (e.g. if an explosion happens, wait till the explosion is over before
// starting any other animation).
if ( m_controls->m_rescue && !m_kart->getKartAnimation() )
{
new RescueAnimation(m_kart);
m_controls->m_rescue=false;
}
} // update
//-----------------------------------------------------------------------------
/** Checks if the kart was overtaken, and if so plays a sound
*/
void NetworkPlayerController::setPosition(int p)
{
if(m_kart->getPosition()<p)
{
World *world = World::getWorld();
//have the kart that did the passing beep.
//I'm not sure if this method of finding the passing kart is fail-safe.
for(unsigned int i = 0 ; i < world->getNumKarts(); i++ )
{
AbstractKart *kart = world->getKart(i);
if(kart->getPosition() == p + 1)
{
kart->beep();
break;
}
}
}
} // setPosition
//-----------------------------------------------------------------------------
/** Called when a kart finishes race.
* /param time Finishing time for this kart.
d*/
void NetworkPlayerController::finishedRace(float time)
{
} // finishedRace
//-----------------------------------------------------------------------------
/** Called when a kart hits or uses a zipper.
*/
void NetworkPlayerController::handleZipper(bool play_sound)
{
m_kart->showZipperFire();
} // handleZipper
//-----------------------------------------------------------------------------
/** Called when a kart hits an item.
* \param item Item that was collected.
* \param add_info Additional info to be used then handling the item. If
* this is -1 (default), the item type is selected
* randomly. Otherwise it contains the powerup or
* attachment for the kart. This is used in network mode to
* let the server determine the powerup/attachment for
* the clients.
*/
void NetworkPlayerController::collectedItem(const Item &item, int add_info, float old_energy)
{
} // collectedItem

View File

@@ -0,0 +1,48 @@
#ifndef NETWORK_PLAYER_CONTROLLER_HPP
#define NETWORK_PLAYER_CONTROLLER_HPP
#include "karts/controller/controller.hpp"
class AbstractKart;
class Player;
class NetworkPlayerController : public Controller
{
protected:
int m_steer_val, m_steer_val_l, m_steer_val_r;
int m_prev_accel;
bool m_prev_brake;
bool m_prev_nitro;
float m_penalty_time;
void steer(float, int);
public:
NetworkPlayerController (AbstractKart *kart,
StateManager::ActivePlayer *_player);
virtual ~NetworkPlayerController ();
void update (float);
void action (PlayerAction action, int value);
void handleZipper (bool play_sound);
void collectedItem (const Item &item, int add_info=-1,
float previous_energy=0);
virtual void skidBonusTriggered();
virtual void setPosition (int p);
virtual bool isPlayerController() const { return false; }
virtual bool isNetworkController() const { return true; }
virtual void reset ();
void resetInputState ();
virtual void finishedRace (float time);
virtual void crashed (const AbstractKart *k) {}
virtual void crashed (const Material *m) {}
// ------------------------------------------------------------------------
/** Callback whenever a new lap is triggered. Used by the AI
* to trigger a recomputation of the way to use, not used for players. */
virtual void newLap(int lap) {}
// ------------------------------------------------------------------------
/** Player will always be able to get a slipstream bonus. */
virtual bool disableSlipstreamBonus() const { return false; }
};
#endif // NETWORK_PLAYER_CONTROLLER_HPP

View File

@@ -35,6 +35,7 @@
#include "karts/skidding.hpp"
#include "karts/rescue_animation.hpp"
#include "modes/world.hpp"
#include "network/network_world.hpp"
#include "race/history.hpp"
#include "states_screens/race_gui_base.hpp"
#include "utils/constants.hpp"
@@ -218,6 +219,10 @@ void PlayerController::action(PlayerAction action, int value)
default:
break;
}
if (NetworkWorld::getInstance()->isRunning())
{
NetworkWorld::getInstance()->controllerAction(this, action, value);
}
} // action

View File

@@ -55,7 +55,6 @@
#include "karts/skidding_properties.hpp"
#include "modes/linear_world.hpp"
#include "modes/profile_world.hpp"
#include "network/network_manager.hpp"
#include "race/race_manager.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/track.hpp"
@@ -294,13 +293,6 @@ void SkiddingAI::update(float dt)
return;
#endif
// The client does not do any AI computations.
if(network_manager->getMode()==NetworkManager::NW_CLIENT)
{
AIBaseController::update(dt);
return;
}
// If the kart needs to be rescued, do it now (and nothing else)
if(isStuck() && !m_kart->getKartAnimation())
{

View File

@@ -59,8 +59,6 @@
#include "karts/max_speed.hpp"
#include "karts/skidding.hpp"
#include "modes/linear_world.hpp"
#include "network/race_state.hpp"
#include "network/network_manager.hpp"
#include "physics/btKart.hpp"
#include "physics/btKartRaycast.hpp"
#include "physics/btUprightConstraint.hpp"
@@ -903,15 +901,6 @@ void Kart::collectedItem(Item *item, int add_info)
default : break;
} // switch TYPE
// Attachments and powerups are stored in the corresponding
// functions (hit{Red,Green}Item), so only coins need to be
// stored here.
if(network_manager->getMode()==NetworkManager::NW_SERVER &&
(type==Item::ITEM_NITRO_BIG || type==Item::ITEM_NITRO_SMALL) )
{
race_state->itemCollected(getWorldKartId(), item->getItemId());
}
if ( m_collected_energy > m_kart_properties->getNitroMax())
m_collected_energy = m_kart_properties->getNitroMax();
m_controller->collectedItem(*item, add_info, old_energy);
@@ -1100,14 +1089,6 @@ void Kart::update(float dt)
m_slipstream->update(dt);
// Store the actual kart controls at the start of update in the server
// state. This makes it easier to reset some fields when they are not used
// anymore (e.g. controls.fire).
if(network_manager->getMode()==NetworkManager::NW_SERVER)
{
race_state->storeKartControls(*this);
}
if (!m_flying)
{
// When really on air, free fly, when near ground, try to glide / adjust for landing
@@ -1994,10 +1975,8 @@ void Kart::updatePhysics(float dt)
updateSliding();
// Only compute the current speed if this is not the client. On a client the
// speed is actually received from the server.
if(network_manager->getMode()!=NetworkManager::NW_CLIENT)
m_speed = getVehicle()->getRigidBody()->getLinearVelocity().length();
// Compute the speed of the kart.
m_speed = getVehicle()->getRigidBody()->getLinearVelocity().length();
// calculate direction of m_speed
const btTransform& chassisTrans = getVehicle()->getChassisWorldTransform();

View File

@@ -31,13 +31,14 @@ using namespace irr;
#include "physics/user_pointer.hpp"
#include "utils/no_copy.hpp"
#include "utils/vec3.hpp"
#include "network/types.hpp"
class Material;
/**
* \ingroup karts
*/
class Moveable: public NoCopy
class Moveable: public NoCopy, public CallbackObject
{
private:
btVector3 m_velocityLC; /**<Velocity in kart coordinates. */

View File

@@ -121,6 +121,7 @@
# include <unistd.h>
# endif
# define _WINSOCKAPI_
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# ifdef _MSC_VER
# include <direct.h>
@@ -138,6 +139,7 @@
#include <IEventReceiver.h>
#include "main_loop.hpp"
#include "achievements/achievements_manager.hpp"
#include "addons/addons_manager.hpp"
#include "addons/inetwork_http.hpp"
#include "addons/news_manager.hpp"
@@ -154,6 +156,7 @@
#include "graphics/referee.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/event_handler.hpp"
#include "guiengine/dialog_queue.hpp"
#include "input/input_manager.hpp"
#include "input/device_manager.hpp"
#include "input/wiimote_manager.hpp"
@@ -167,6 +170,14 @@
#include "modes/demo_world.hpp"
#include "modes/profile_world.hpp"
#include "network/network_manager.hpp"
#include "network/client_network_manager.hpp"
#include "network/server_network_manager.hpp"
#include "network/protocol_manager.hpp"
#include "network/protocols/server_lobby_room_protocol.hpp"
#include "online/current_user.hpp"
#include "online/http_manager.hpp"
#include "online/profile_manager.hpp"
#include "online/servers_manager.hpp"
#include "race/grand_prix_manager.hpp"
#include "race/highscore_manager.hpp"
#include "race/history.hpp"
@@ -417,6 +428,7 @@ void cmdLineHelp(char* invocation)
" --profile-time=n Enable automatic driven profile mode for n "
"seconds.\n"
" --no-graphics Do not display the actual race.\n"
" --with-profile Enables the profile mode.\n"
" --demo-mode t Enables demo mode after t seconds idle time in "
"main menu.\n"
" --demo-tracks t1,t2 List of tracks to be used in demo mode. No\n"
@@ -428,13 +440,11 @@ void cmdLineHelp(char* invocation)
// " --history=n Replay history file 'history.dat' using:\n"
// " n=1: recorded positions\n"
// " n=2: recorded key strokes\n"
//" --server[=port] This is the server (running on the specified "
// "port).\n"
//" --client=ip This is a client, connect to the specified ip"
// " address.\n"
//" --port=n Port number to use.\n"
//" --numclients=n Number of clients to wait for (server "
// "only).\n"
" --server Start a server (not a playing client).\n"
" --login=s Automatically sign in (set the login).\n"
" --password=s Automatically sign in (set the password).\n"
" --port=n Port number to use.\n"
" --max-players=n Maximum number of clients (server only).\n"
" --no-console Does not write messages in the console but to\n"
" stdout.log.\n"
" --console Write messages in the console and files\n"
@@ -624,6 +634,9 @@ int handleCmdLine(int argc, char **argv)
int n;
char s[1024];
bool try_login = false;
irr::core::stringw login, password;
for(int i=1; i<argc; i++)
{
@@ -705,23 +718,27 @@ int handleCmdLine(int argc, char **argv)
{
AIBaseController::enableDebug();
}
else if(sscanf(argv[i], "--server=%d",&n)==1)
else if(sscanf(argv[i], "--port=%d",&n))
{
network_manager->setMode(NetworkManager::NW_SERVER);
UserConfigParams::m_server_port = n;
}
else if( !strcmp(argv[i], "--server") )
{
network_manager->setMode(NetworkManager::NW_SERVER);
NetworkManager::getInstance<ServerNetworkManager>();
Log::info("main", "Creating a server network manager.");
}
else if( sscanf(argv[i], "--port=%d", &n) )
else if( sscanf(argv[i], "--max-players=%d", &n) )
{
UserConfigParams::m_server_port=n;
UserConfigParams::m_server_max_players=n;
}
else if( sscanf(argv[i], "--client=%1023s", s) )
else if( sscanf(argv[i], "--login=%1023s", s) )
{
network_manager->setMode(NetworkManager::NW_CLIENT);
UserConfigParams::m_server_address=s;
login = s;
try_login = true;
}
else if( sscanf(argv[i], "--password=%1023s", s) )
{
password = s;
}
else if ( sscanf(argv[i], "--gfx=%d", &n) )
{
@@ -1007,6 +1024,9 @@ int handleCmdLine(int argc, char **argv)
race_manager->setNumLaps(999999); // profile end depends on time
}
else if( !strcmp(argv[i], "--no-graphics") )
{
}
else if( !strcmp(argv[i], "--with-profile") )
{
// Set default profile mode of 1 lap if we haven't already set one
if (!ProfileWorld::isProfileMode()) {
@@ -1122,6 +1142,19 @@ int handleCmdLine(int argc, char **argv)
UserConfigParams::m_music = false;// and music when profiling
}
if (try_login)
{
irr::core::stringw s;
Online::CurrentUser::SignInRequest* request =
Online::CurrentUser::get()->requestSignIn(login, password, false, false);
Online::HTTPManager::get()->synchronousRequest(request);
if (request->isSuccess())
{
Log::info("Main", "Logged in from command line.");
}
}
return 1;
} // handleCmdLine
@@ -1189,6 +1222,8 @@ void initRest()
// to network_http (since the thread might use network_http, otherwise
// a race condition can be introduced resulting in a crash).
INetworkHttp::get()->startNetworkThread();
Online::HTTPManager::get()->startNetworkThread();
AchievementsManager::get()->init();
music_manager = new MusicManager();
sfx_manager = new SFXManager();
// The order here can be important, e.g. KartPropertiesManager needs
@@ -1202,7 +1237,6 @@ void initRest()
powerup_manager = new PowerupManager ();
attachment_manager = new AttachmentManager ();
highscore_manager = new HighscoreManager ();
network_manager = new NetworkManager ();
KartPropertiesManager::addKartSearchDir(
file_manager->getAddonsFile("karts/"));
track_manager->addTrackSearchDir(
@@ -1246,15 +1280,25 @@ static void cleanSuperTuxKart()
if(INetworkHttp::get())
INetworkHttp::get()->stopNetworkThread();
if(Online::HTTPManager::isRunning())
Online::HTTPManager::get()->stopNetworkThread();
//delete in reverse order of what they were created in.
//see InitTuxkart()
Online::ServersManager::deallocate();
Online::ProfileManager::deallocate();
AchievementsManager::deallocate();
Online::CurrentUser::deallocate();
GUIEngine::DialogQueue::deallocate();
Referee::cleanup();
if(ReplayPlay::get()) ReplayPlay::destroy();
if(race_manager) delete race_manager;
INetworkHttp::destroy();
if(news_manager) delete news_manager;
if(addons_manager) delete addons_manager;
if(network_manager) delete network_manager;
NetworkManager::kill();
if(grand_prix_manager) delete grand_prix_manager;
if(highscore_manager) delete highscore_manager;
if(attachment_manager) delete attachment_manager;
@@ -1278,6 +1322,7 @@ static void cleanSuperTuxKart()
StateManager::deallocate();
GUIEngine::EventHandler::deallocate();
Online::HTTPManager::deallocate();
} // cleanSuperTuxKart
//=============================================================================
@@ -1377,6 +1422,15 @@ int main(int argc, char *argv[] )
//handleCmdLine() needs InitTuxkart() so it can't be called first
if(!handleCmdLine(argc, argv)) exit(0);
// load the network manager
// If the server has been created (--server option), this will do nothing (just a warning):
NetworkManager::getInstance<ClientNetworkManager>();
NetworkManager::getInstance()->run();
if (NetworkManager::getInstance()->isServer())
{
ProtocolManager::getInstance()->requestStart(new ServerLobbyRoomProtocol());
}
addons_manager->checkInstalledAddons();
// Load addons.xml to get info about addons even when not
@@ -1389,6 +1443,20 @@ int main(int argc, char *argv[] )
}
}
// no graphics, and no profile mode
if (ProfileWorld::isNoGraphics() && !ProfileWorld::isProfileMode())
{
// hack to have a running game slot :
PtrVector<PlayerProfile>& players = UserConfigParams::m_all_players;
if (UserConfigParams::m_default_player.toString().size() > 0)
for (int n=0; n<players.size(); n++)
if (players[n].getName() == UserConfigParams::m_default_player.toString())
unlock_manager->setCurrentSlot(players[n].getUniqueID());
main_loop->run();
throw "salut";
}
if(!UserConfigParams::m_no_start_screen)
{
StateManager::get()->pushScreen(StoryModeLobbyScreen::getInstance());
@@ -1451,7 +1519,7 @@ int main(int argc, char *argv[] )
// Create player and associate player with keyboard
StateManager::get()->createActivePlayer(
UserConfigParams::m_all_players.get(0), device );
UserConfigParams::m_all_players.get(0), device, NULL);
if (kart_properties_manager->getKart(UserConfigParams::m_default_kart) == NULL)
{
@@ -1474,7 +1542,6 @@ int main(int argc, char *argv[] )
StateManager::get()->enterGameState();
}
// If an important news message exists it is shown in a popup dialog.
const core::stringw important_message =
news_manager->getImportantMessage();
@@ -1492,7 +1559,7 @@ int main(int argc, char *argv[] )
{
// This will setup the race manager etc.
history->Load();
network_manager->setupPlayerKartInfo();
race_manager->setupPlayerKartInfo();
race_manager->startNew(false);
main_loop->run();
// well, actually run() will never return, since
@@ -1501,20 +1568,6 @@ int main(int argc, char *argv[] )
exit(-3);
}
// Initialise connection in case that a command line option was set
// configuring a client or server. Otherwise this function does nothing
// here (and will be called again from the network gui).
if(!network_manager->initialiseConnections())
{
Log::error("main", "Problems initialising network connections,\n"
"Running in non-network mode.");
}
// On the server start with the network information page for now
if(network_manager->getMode()==NetworkManager::NW_SERVER)
{
// TODO - network menu
//menu_manager->pushMenu(MENUID_NETWORK_GUI);
}
// Not replaying
// =============
if(!ProfileWorld::isProfileMode())
@@ -1524,7 +1577,7 @@ int main(int argc, char *argv[] )
// Quickstart (-N)
// ===============
// all defaults are set in InitTuxkart()
network_manager->setupPlayerKartInfo();
race_manager->setupPlayerKartInfo();
race_manager->startNew(false);
}
}
@@ -1533,7 +1586,7 @@ int main(int argc, char *argv[] )
// Profiling
// =========
race_manager->setMajorMode (RaceManager::MAJOR_MODE_SINGLE);
network_manager->setupPlayerKartInfo();
race_manager->setupPlayerKartInfo();
race_manager->startNew(false);
}
main_loop->run();

View File

@@ -30,7 +30,9 @@
#include "input/wiimote_manager.hpp"
#include "modes/profile_world.hpp"
#include "modes/world.hpp"
#include "network/network_manager.hpp"
#include "network/protocol_manager.hpp"
#include "network/network_world.hpp"
#include "online/http_manager.hpp"
#include "race/race_manager.hpp"
#include "states_screens/state_manager.hpp"
#include "utils/profiler.hpp"
@@ -74,9 +76,9 @@ float MainLoop::getLimitedDt()
// Throttle fps if more than maximum, which can reduce
// the noise the fan on a graphics card makes.
// When in menus, reduce FPS much, it's not necessary to push to the maximum for plain menus
const int max_fps = (StateManager::get()->throttleFPS() ? 35 : UserConfigParams::m_max_fps);
const int max_fps = 35;//(StateManager::get()->throttleFPS() ? 35 : UserConfigParams::m_max_fps);
const int current_fps = (int)(1000.0f/dt);
if( current_fps > max_fps && !ProfileWorld::isNoGraphics())
if( current_fps > max_fps && !ProfileWorld::isProfileMode())
{
int wait_time = 1000/max_fps - 1000/current_fps;
if(wait_time < 1) wait_time = 1;
@@ -95,22 +97,12 @@ float MainLoop::getLimitedDt()
*/
void MainLoop::updateRace(float dt)
{
// Server: Send the current position and previous controls to all clients
// Client: send current controls to server
// But don't do this if the race is in finish phase (otherwise
// messages can be mixed up in the race manager)
if(!World::getWorld()->isFinishPhase())
network_manager->sendUpdates();
if(ProfileWorld::isProfileMode()) dt=1.0f/60.0f;
// Again, only receive updates if the race isn't over - once the
// race results are displayed (i.e. game is in finish phase)
// messages must be handled by the normal update of the network
// manager
if(!World::getWorld()->isFinishPhase())
network_manager->receiveUpdates();
World::getWorld()->updateWorld(dt);
if (NetworkWorld::getInstance<NetworkWorld>()->isRunning())
NetworkWorld::getInstance<NetworkWorld>()->update(dt);
else
World::getWorld()->updateWorld(dt);
} // updateRace
//-----------------------------------------------------------------------------
@@ -128,13 +120,8 @@ void MainLoop::run()
m_prev_time = m_curr_time;
float dt = getLimitedDt();
network_manager->update(dt);
if (World::getWorld()) // race is active if world exists
{
// Busy wait if race_manager is active (i.e. creating of world is done)
// till all clients have reached this state.
if (network_manager->getState()==NetworkManager::NS_READY_SET_GO_BARRIER) continue;
updateRace(dt);
} // if race is active
@@ -163,7 +150,24 @@ void MainLoop::run()
PROFILER_PUSH_CPU_MARKER("IrrDriver update", 0x00, 0x00, 0x7F);
irr_driver->update(dt);
PROFILER_POP_CPU_MARKER();
PROFILER_PUSH_CPU_MARKER("Protocol manager update", 0x7F, 0x00, 0x7F);
ProtocolManager::getInstance()->update();
PROFILER_POP_CPU_MARKER();
PROFILER_PUSH_CPU_MARKER("Database polling update", 0x00, 0x7F, 0x7F);
Online::HTTPManager::get()->update(dt);
PROFILER_POP_CPU_MARKER();
PROFILER_SYNC_FRAME();
}
else if (!m_abort && ProfileWorld::isNoGraphics())
{
PROFILER_PUSH_CPU_MARKER("Protocol manager update", 0x7F, 0x00, 0x7F);
ProtocolManager::getInstance()->update();
PROFILER_POP_CPU_MARKER();
}
PROFILER_SYNC_FRAME();
PROFILER_POP_CPU_MARKER();
} // while !m_exit

View File

@@ -35,7 +35,7 @@
#include "physics/physics.hpp"
#include "states_screens/credits.hpp"
#include "states_screens/cutscene_gui.hpp"
#include "states_screens/kart_selection.hpp"
#include "states_screens/offline_kart_selection.hpp"
#include "states_screens/main_menu_screen.hpp"
#include "tracks/track.hpp"
#include "tracks/track_object.hpp"
@@ -384,7 +384,7 @@ void CutsceneWorld::enterRaceOverState()
slot->setFirstTime(false);
unlock_manager->save();
KartSelectionScreen* s = KartSelectionScreen::getInstance();
KartSelectionScreen* s = OfflineKartSelectionScreen::getInstance();
s->setMultiplayer(false);
s->setGoToOverworldNext();
StateManager::get()->pushScreen( s );

View File

@@ -21,7 +21,6 @@
#include "guiengine/modaldialog.hpp"
#include "input/device_manager.hpp"
#include "input/input_manager.hpp"
#include "network/network_manager.hpp"
#include "race/race_manager.hpp"
#include "tracks/track.hpp"
#include "tracks/track_manager.hpp"
@@ -141,7 +140,7 @@ bool DemoWorld::updateIdleTimeAndStartDemo(float dt)
// Use keyboard 0 by default in --no-start-screen
device = input_manager->getDeviceList()->getKeyboard(0);
StateManager::get()->createActivePlayer(
UserConfigParams::m_all_players.get(0), device );
UserConfigParams::m_all_players.get(0), device , NULL);
// ASSIGN should make sure that only input from assigned devices
// is read.
input_manager->getDeviceList()->setAssignMode(ASSIGN);
@@ -149,7 +148,7 @@ bool DemoWorld::updateIdleTimeAndStartDemo(float dt)
m_do_demo = true;
race_manager->setNumKarts(m_num_karts);
race_manager->setLocalKartInfo(0, "tux");
network_manager->setupPlayerKartInfo();
race_manager->setupPlayerKartInfo();
race_manager->startSingleRace(m_demo_tracks[0], m_num_laps, false);
m_demo_tracks.push_back(m_demo_tracks[0]);
m_demo_tracks.erase(m_demo_tracks.begin());

Some files were not shown because too many files have changed in this diff Show More