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
17
data/achievements.xml
Normal 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>
|
||||
|
||||
@@ -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
|
After Width: | Height: | Size: 66 KiB |
BIN
data/gui/menu_online_focus.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
47
data/gui/online/change_password.stkgui
Normal 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>
|
||||
36
data/gui/online/create_server.stkgui
Normal 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>
|
||||
51
data/gui/online/lobby.stkgui
Normal 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>
|
||||
32
data/gui/online/lobby_settings.stkgui
Normal 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>
|
||||
59
data/gui/online/login_dialog.stkgui
Normal 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>
|
||||
51
data/gui/online/main.stkgui
Normal 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>
|
||||
BIN
data/gui/online/menu_create_server.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
data/gui/online/menu_create_server_hover.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
data/gui/online/menu_find_server.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
data/gui/online/menu_find_server_hover.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
data/gui/online/menu_quick_play.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
data/gui/online/menu_quick_play_hover.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
19
data/gui/online/notification_dialog.stkgui
Normal 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>
|
||||
23
data/gui/online/profile_achievements.stkgui
Normal 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>
|
||||
37
data/gui/online/profile_friends.stkgui
Normal 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>
|
||||
25
data/gui/online/profile_overview.stkgui
Normal 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>
|
||||
29
data/gui/online/profile_settings.stkgui
Normal 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>
|
||||
23
data/gui/online/recovery_info.stkgui
Normal 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>
|
||||
46
data/gui/online/recovery_input.stkgui
Normal 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>
|
||||
23
data/gui/online/registration_info.stkgui
Normal 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>
|
||||
61
data/gui/online/registration_input.stkgui
Normal 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>
|
||||
39
data/gui/online/registration_terms.stkgui
Normal 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>
|
||||
33
data/gui/online/server_info_dialog.stkgui
Normal 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>
|
||||
17
data/gui/online/server_selection.stkgui
Normal 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>
|
||||
41
data/gui/online/user_info_dialog.stkgui
Normal 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>
|
||||
24
data/gui/online/user_search.stkgui
Normal 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>
|
||||
27
data/gui/online/vote_dialog.stkgui
Normal 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>
|
||||
21
data/web.tuxfamily.org.pem
Normal 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
@@ -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);
|
||||
|
||||
160
sources.cmake
@@ -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
|
||||
)
|
||||
|
||||
209
src/achievements/achievement.cpp
Normal 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);
|
||||
}
|
||||
|
||||
101
src/achievements/achievement.hpp
Normal 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*/
|
||||
87
src/achievements/achievement_info.cpp
Normal 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;
|
||||
}
|
||||
87
src/achievements/achievement_info.hpp
Normal 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*/
|
||||
247
src/achievements/achievements_manager.cpp
Normal 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;
|
||||
}
|
||||
70
src/achievements/achievements_manager.hpp
Normal 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*/
|
||||
153
src/achievements/achievements_slot.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
64
src/achievements/achievements_slot.hpp
Normal 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*/
|
||||
@@ -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; }
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <vector>
|
||||
|
||||
#ifdef WIN32
|
||||
# include <winsock2.h>
|
||||
# include <WinSock2.h>
|
||||
#endif
|
||||
#include <curl/curl.h>
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
82
src/guiengine/dialog_queue.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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 */);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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() { }
|
||||
};
|
||||
|
||||
|
||||
|
||||
757
src/guiengine/widgets/CGUISTKListBox.cpp
Normal 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
|
||||
|
||||
|
||||
198
src/guiengine/widgets/CGUISTKListBox.h
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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; }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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!
|
||||
|
||||
@@ -68,6 +68,7 @@ namespace GUIEngine
|
||||
void clearListeners();
|
||||
|
||||
irr::core::stringw getText() const;
|
||||
void setPasswordBox(bool passwordBox, wchar_t passwordChar = L'*');
|
||||
|
||||
virtual void elementRemoved();
|
||||
};
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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];
|
||||
|
||||
368
src/karts/controller/network_player_controller.cpp
Normal 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
|
||||
48
src/karts/controller/network_player_controller.hpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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. */
|
||||
|
||||
125
src/main.cpp
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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());
|
||||
|
||||