diff --git a/.gitignore b/.gitignore index 29e3a14..a57274e 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,8 @@ share/python-wheels/ .installed.cfg *.egg MANIFEST +.buildozer +bin # Installer logs pip-log.txt diff --git a/Compilation.md b/Compilation.md new file mode 100644 index 0000000..ef99cf7 --- /dev/null +++ b/Compilation.md @@ -0,0 +1,36 @@ +# Compilation instructions + +## Debug + +### Compilation of a debug version + +`python -m buildozer -v android debug` + +### Launch the debug version on a device connected to the computer + +`python -m buildozer -v android deploy run logcat | grep python` + +## Release + +### Creation of the app signing key + +```bash +keytool -genkey -v -keystore ~/keystores/Postrias.keystore -alias Postrias -keyalg RSA -keysize 2048 -validity 10000 +keytool -importkeystore -srckeystore ~/keystores/Postrias.keystore -destkeystore ~/keystores/Postrias.keystore -deststoretype pkcs12 +``` + +### Compilation of a release version + +```bash +export P4A_RELEASE_KEYALIAS="Postrias" +export P4A_RELEASE_KEYSTORE=~/keystores/Postrias.keystore +export P4A_RELEASE_KEYSTORE_PASSWD= +export P4A_RELEASE_KEYALIAS_PASSWD= +python -m buildozer android release +``` + +## Bug fix + +### Java Heap Space error + +`export GRADLE_OPTS="-Xms1724m -Xmx5048m -Dorg.gradle.jvmargs='-Xms1724m -Xmx5048m'"` \ No newline at end of file diff --git a/buildozer.spec b/buildozer.spec index d9b0d2a..95c6794 100644 --- a/buildozer.spec +++ b/buildozer.spec @@ -4,16 +4,16 @@ title = Postrias # (str) Package name -package.name = tramwaycollector +package.name = postrias # (str) Package domain (needed for android/ios packaging) -package.domain = lupa.dev.studio.com +package.domain = lupadevstudio.com # (str) Source code where the main.py live source.dir = . # (list) Source files to include (let empty to include all the files) -source.include_exts = py,png,jpg,kv,atlas,json,txt,ttf,wav,ico,ogg,otf +source.include_exts = py,png,jpg,kv,atlas,json,txt,ttf,wav,ico,ogg,otf,mp3 # (list) List of inclusions using pattern matching #source.include_patterns = assets/*,images/*.png @@ -37,7 +37,7 @@ version = 2.0.0 # (list) Application requirements # comma separated e.g. requirements = sqlite3,kivy -requirements = python3,kivy,androidstorage4kivy +requirements = python3,kivy # (str) Custom source folders for requirements # Sets custom source for any requirements with recipes @@ -47,10 +47,10 @@ requirements = python3,kivy,androidstorage4kivy #presplash.filename = ./resources/logo_collector_1024.png # (str) Icon of the application -icon.filename = ./resources/logo_collector_1024.png +icon.filename = ./resources/logo.png # (str) Supported orientation (one of landscape, sensorLandscape, portrait or all) -orientation = portrait +orientation = landscape # (list) List of service to declare #services = NAME:ENTRYPOINT_TO_PY,NAME2:ENTRYPOINT2_TO_PY @@ -73,13 +73,14 @@ osx.kivy_version = 2.1.0 # # (bool) Indicate if the application should be fullscreen or not -fullscreen = 0 +fullscreen = 1 # (string) Presplash background color (for android toolchain) # Supported formats are: #RRGGBB #AARRGGBB or one of the following names: # red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray, # darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy, # olive, purple, silver, teal. +# Postrias res : ec1c24 android.presplash_color = #e6e6e6 # (string) Presplash animation using Lottie format. @@ -93,7 +94,7 @@ android.presplash_lottie = resources/presplash.json #icon.adaptive_background.filename = %(source.dir)s/data/icon_bg.png # (list) Permissions -android.permissions = READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE, INTERNET +android.permissions = INTERNET, ACCESS_NETWORK_STATE # (list) features (adds uses-feature -tags to manifest) #android.features = android.hardware.usb.host @@ -175,7 +176,7 @@ android.sdk = 34 # (list) List of Java files to add to the android project (can be java or a # directory containing the files) -#android.add_src = +android.add_src = src # (list) Android AAR archives to add #android.add_aars = @@ -187,7 +188,7 @@ android.sdk = 34 #android.add_assets = # (list) Gradle dependencies to add -#android.gradle_dependencies = +android.gradle_dependencies = com.google.android.gms:play-services-ads:20.3.0 # (bool) Enable AndroidX support. Enable when 'android.gradle_dependencies' # contains an 'androidx' package, or any package from Kotlin source. @@ -239,7 +240,7 @@ android.sdk = 34 #android.wakelock = False # (list) Android application meta-data to set (key=value format) -#android.meta_data = +android.meta_data = com.google.android.gms.ads.APPLICATION_ID=ca-app-pub-3940256099942544~3347511713 # (list) Android library project to add (will be added in the # project.properties automatically.) diff --git a/kivads.py b/kivads.py new file mode 100644 index 0000000..1954263 --- /dev/null +++ b/kivads.py @@ -0,0 +1,384 @@ +from kivy.logger import Logger +from kivy.metrics import dp +from kivy.properties import BooleanProperty +from kivy.utils import platform + +if platform == "android": + from android import PythonJavaClass, autoclass, java_method, mActivity + from android.runnable import run_on_ui_thread + + context = mActivity.getApplicationContext() + MobileAds = autoclass("com.google.android.gms.ads.MobileAds") + AdRequest = autoclass("com.google.android.gms.ads.AdRequest") + AdRequestBuilder = autoclass( + "com.google.android.gms.ads.AdRequest$Builder") + RequestConfigurationBuilder = autoclass( + "com.google.android.gms.ads.RequestConfiguration$Builder" + ) + RequestConfiguration = autoclass( + "com.google.android.gms.ads.RequestConfiguration") + + _InterstitialAd = autoclass( + "com.google.android.gms.ads.interstitial.InterstitialAd" + ) + AdView = autoclass("com.google.android.gms.ads.AdView") + BListener = autoclass("org.org.kivads.BListener") + InterstitialCallback = autoclass("org.org.kivads.ICallback") + FullScreenContentCallback = autoclass("org.org.kivads.FullScreen") + Gravity = autoclass("android.view.Gravity") + LayoutParams = autoclass("android.view.ViewGroup$LayoutParams") + LinearLayout = autoclass("android.widget.LinearLayout") + AdSize = autoclass("com.google.android.gms.ads.AdSize") + View = autoclass("android.view.View") + activity = autoclass("org.kivy.android.PythonActivity") + _RewardedAd = autoclass("com.google.android.gms.ads.rewarded.RewardedAd") + RewardCallback = autoclass("org.org.kivads.RCallback") + _RewardedInterstitialAd = autoclass( + "com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd" + ) + RewardInterstitialCallback = autoclass("org.org.kivads.RICallback") + + class RewardEarnedListener(PythonJavaClass): + __javainterfaces__ = [ + "com/google/android/gms/ads/OnUserEarnedRewardListener"] + + __javacontext__ = "app" + + callback = None + + rewarded = False + + @java_method("(Lcom/google/android/gms/ads/rewarded/RewardItem;)V") + def onUserEarnedReward(self, reward): + self.reward = reward + # Run the `on_reward` callback that the user has provided + if self.callback: + self.callback() + self.rewarded = True + + class RewardedInterstitial: + + callback = RewardInterstitialCallback() + + reward_listener = RewardEarnedListener() + + full_screen_callback = FullScreenContentCallback() + + def __init__(self, UnitID, on_reward=None): + if platform == "android": + Logger.info("KivAds: Loading Interstitial Rewarded Ad") + self.on_reward = on_reward + self.callback.loaded = False + self.callback.mRewardedIinterstitialAd = None + self.load(UnitID) + + @run_on_ui_thread + def load(self, UnitID): + + if not self.callback.loaded: + builder = AdRequestBuilder().build() + _RewardedInterstitialAd.load( + context, UnitID, builder, self.callback) + else: + Logger.info( + "KivAds: Interstitial Ad already Loaded and Ready to Show") + + @run_on_ui_thread + def show(self, immersive=False): + + if self.callback.loaded: + if immersive: + self.callback.mRewardedInterstitialAd.setImmersiveMode( + True) + # If user has given a callback we set it here or else we leave it as None + if self.on_reward: + self.reward_listener.callback = self.on_reward + # Set the full screen content callback + self.full_screen_callback.dismissed = False + self.callback.mRewardedInterstitialAd.setFullScreenContentCallback = ( + self.full_screen_callback + ) + self.callback.mRewardedInterstitialAd.show( + mActivity, self.reward_listener) + self.callback.loaded = False + else: + Logger.info("KivAds:The ad hasn't loaded yet. Not showing") + + def is_loaded(self): + return self.callback.loaded + + def is_dismissed(self): + if self.full_screen_callback.dismissed: + return True + else: + False + + def get_reward_amount(self): + return self.reward_listener.reward.getAmount() + + def get_reward_type(self): + return self.reward_listener.reward.getType() + + class RewardedAd: + + callback = RewardCallback() + + reward_listener = RewardEarnedListener() + + full_screen_callback = FullScreenContentCallback() + + def __init__(self, UnitID, on_reward=None): + if platform == "android": + Logger.info("KivAds: Loading Rewarded Ad") + self.on_reward = on_reward + self.callback.loaded = False + self.callback.mRewardedAd = None + self.load(UnitID) + + @run_on_ui_thread + def load(self, UnitID): + if not self.callback.loaded: + builder = AdRequestBuilder().build() + _RewardedAd.load(context, UnitID, builder, self.callback) + else: + Logger.info( + "KivAds: Interstitial Ad already Loaded and Ready to Show") + + @run_on_ui_thread + def show(self, immersive=False): + if self.callback.loaded: + if immersive: + self.callback.mRewardedAd.setImmersiveMode(True) + # If user has given a callback we set it here or else we leave it as None + if self.on_reward: + self.reward_listener.callback = self.on_reward + # Set the full screen content callback + self.full_screen_callback.dismissed = False + self.callback.mRewardedAd.setFullScreenContentCallback = ( + self.full_screen_callback + ) + self.callback.mRewardedAd.show(mActivity, self.reward_listener) + self.callback.loaded = False + else: + Logger.info("KivAds:The ad hasn't loaded yet. Not showing") + + def is_loaded(self): + return self.callback.loaded + + def is_dismissed(self): + if self.full_screen_callback.dismissed: + return True + else: + False + + def get_reward_amount(self): + return self.reward_listener.reward.getAmount() + + def get_reward_type(self): + return self.reward_listener.reward.getType() + + class BannerAd: + + adview = AdView(context) + + adlistener = BListener() + + showing = False + + def __init__(self, UnitID, size=None, bottom=False): + if platform == "android": + Logger.info("KivAds: Loading Banner Ad") + self.adlistener.loaded = False + self.load(UnitID, size, bottom) + + @run_on_ui_thread + def load(self, UnitID, size, bottom): + if not self.adlistener.loaded: + if isinstance(size, tuple): + banner_size = AdSize(size[0], size[1]) + elif isinstance(size, int): + banner_size = AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize( + context, size / dp(1) + ) + elif size == "BANNER": + banner_size = AdSize.BANNER + elif size == "LARGE_BANNER": + banner_size = AdSize.LARGE_BANNER + elif size == "MEDIUM_RECTANGLE": + banner_size = AdSize.MEDIUM_RECTANGLE + elif size == "FULL_BANNER": + banner_size = AdSize.FULL_BANNER + elif size == "LEADERBOARD": + banner_size = AdSize.LEADERBOARD + else: + banner_size = AdSize.SMART_BANNER + self.adview.setAdSize(banner_size) + self.adview.setAdUnitId(UnitID) + self.adview.setVisibility(View.GONE) + self.adview.setAdListener(self.adlistener) + + layout = LinearLayout(context) + layout.addView(self.adview) + layoutParams = LayoutParams( + LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT + ) + layout.setLayoutParams(layoutParams) + if bottom: + layout.setGravity(Gravity.BOTTOM) + activity.addContentView(layout, layoutParams) + builder = AdRequestBuilder().build() + self.adview.loadAd(builder) + else: + Logger.info( + "KivAds: Banner Ad already loaded. Call show() method to display" + ) + + @run_on_ui_thread + def show(self): + if self.adlistener.loaded: + if not self.showing: + self.adview.setVisibility(View.VISIBLE) + self.showing = True + else: + Logger.info( + "KivAds: Banner Ad already showing, Ignoring this function call" + ) + else: + Logger.info("KivAds: Banner Ad not loaded, not showing") + + @run_on_ui_thread + def hide(self): + self.adview.setVisibility(View.GONE) + self.showing = False + + def is_loaded(self): + return self.adlistener.loaded + + def is_clicked(self): + return self.adlistener.clicked + + class InterstitialAd: + + callback = InterstitialCallback() + + full_screen_callback = FullScreenContentCallback() + + def __init__(self, UnitID): + if platform == "android": + Logger.info("KivAds: Loading Interstitial Ad") + self.callback.loaded = False + self.callback.mInterstitialAd = None + self.load(UnitID) + + @run_on_ui_thread + def load(self, UnitID): + if not self.callback.loaded: + builder = AdRequestBuilder().build() + _InterstitialAd.load( + context, + UnitID, + builder, + self.callback, + ) + else: + Logger.info( + "KivAds:Interstitial Ad already Loaded and Ready to Show") + + @run_on_ui_thread + def show(self, immersive=False): + if self.callback.loaded: + self.full_screen_callback.dismissed = False + self.callback.mInterstitialAd.setFullScreenContentCallback( + self.full_screen_callback + ) + if immersive: + self.callback.mInterstitialAd.setImmersiveMode(True) + self.callback.mInterstitialAd.show(mActivity) + self.callback.loaded = False + else: + Logger.warning("KivAds:The ad hasn't loaded yet. Not showing") + + def is_loaded(self): + return self.callback.loaded + + def is_dismissed(self): + if self.full_screen_callback.dismissed: + return True + else: + False + + class KivAds: + + initialized = False + + def __init__(self, show_child=False, rating=None, test_id=None, *args): + if platform == "android": + Logger.info("KivAds: Running on Android") + self.initialize_connection(show_child, rating, test_id) + else: + Logger.warning("KivAds: Not on android, Ads will not be shown") + + def initialize_connection(self, show_child, rating, test_id): + Logger.info("KivAds: Initializing Google SDK connection") + self.initialized = True + # Set if to show child ads or not + if show_child: + requestConfiguration = ( + RequestConfigurationBuilder().setTagForChildDirectedTreatment( + RequestConfiguration.TAG_FOR_CHILD_DIRECTED_TREATMENT_TRUE + ) + ) + else: + requestConfiguration = ( + RequestConfigurationBuilder().setTagForChildDirectedTreatment( + RequestConfiguration.TAG_FOR_CHILD_DIRECTED_TREATMENT_FALSE + ) + ) + # Set Content Rating levels + if rating == "G": + requestConfiguration.setMaxAdContentRating( + RequestConfiguration.MAX_AD_CONTENT_RATING_G + ) + elif rating == "PG": + requestConfiguration.setMaxAdContentRating( + RequestConfiguration.MAX_AD_CONTENT_RATING_PG + ) + elif rating == "T": + requestConfiguration.setMaxAdContentRating( + RequestConfiguration.MAX_AD_CONTENT_RATING_T + ) + elif rating == "MA": + requestConfiguration.setMaxAdContentRating( + RequestConfiguration.MAX_AD_CONTENT_RATING_MA + ) + + # Add the test devices if there are any + if test_id: + requestConfiguration.setTestDeviceIds(test_id) + MobileAds.setRequestConfiguration(requestConfiguration.build()) + MobileAds.initialize(context) + + def is_intialized(self): + return self.initialized + + class TestID: + + """This class contains various TestIDs that can be used while you are tesing your app. + Remeber to change these when you do the final build for your app or you won't earn any money. + """ + + INTERSTITIAL = "ca-app-pub-3940256099942544/1033173712" + """ Test id for Interstitial ads + """ + + BANNER = "ca-app-pub-3940256099942544/6300978111" + """ Test id for Banner Ads + """ + + REWARD = "ca-app-pub-3940256099942544/5224354917" + """ Test id for Reward Video Ads + """ + + REWARD_INTERSTITIAL = "ca-app-pub-3940256099942544/5354046379" + """ Test id for Reward Interstitial Ads + """ diff --git a/licenses/dinosaur_icon.md b/licenses/dinosaur_icon.md new file mode 100644 index 0000000..f2bbc97 --- /dev/null +++ b/licenses/dinosaur_icon.md @@ -0,0 +1 @@ +Dinosaur icons created by Smashicons - Flaticon \ No newline at end of file diff --git a/main.py b/main.py index e748434..130e431 100644 --- a/main.py +++ b/main.py @@ -10,19 +10,37 @@ ### Python imports ### +import os import platform os_name = platform.system() if os_name == "Windows": - import os os.environ['KIVY_TEXT'] = 'pil' ### Kivy imports ### +# Remove the red dots when right-clicking +from kivy.config import Config +Config.set("input", "mouse", "mouse,disable_multitouch") + from kivy.app import App from kivy.uix.screenmanager import ScreenManager, NoTransition, Screen from kivy.uix.widget import Widget from kivy.core.window import Window + +### Ads imports ### + +from kivy.utils import platform +if platform == "android": + from kivads import ( + BannerAd, + InterstitialAd, + KivAds, + RewardedAd, + RewardedInterstitial, + TestID, + ) + ### Module imports ### from tools.path import ( @@ -90,6 +108,16 @@ def build(self): """ Window.clearcolor = (0, 0, 0, 1) self.icon = PATH_IMAGES + "logo.png" + # self.ads = KivAds() + # self.interstitial = InterstitialAd(TestID.INTERSTITIAL) + # self.banner = BannerAd(TestID.BANNER, int(Window.width)) + # self.reward = RewardedAd(TestID.REWARD, self.reward_callback) + # self.reward_interstitial = RewardedInterstitial( + # TestID.REWARD_INTERSTITIAL, self.reward_callback + # ) + + # def reward_callback(self, *args): + # print("ADS REWARD") def on_start(self): if MOBILE_MODE: diff --git a/resources/images/achievements_logo.png b/resources/images/achievements_logo.png new file mode 100644 index 0000000..33d8df9 Binary files /dev/null and b/resources/images/achievements_logo.png differ diff --git a/resources/images/answer_background.jpg b/resources/images/answer_background.jpg new file mode 100644 index 0000000..fe9896f Binary files /dev/null and b/resources/images/answer_background.jpg differ diff --git a/resources/images/answer_background.png b/resources/images/answer_background.png deleted file mode 100755 index b616291..0000000 Binary files a/resources/images/answer_background.png and /dev/null differ diff --git a/resources/images/back_arrow.png b/resources/images/back_arrow.png index 4170786..d153e9c 100644 Binary files a/resources/images/back_arrow.png and b/resources/images/back_arrow.png differ diff --git a/resources/images/card_layout.png b/resources/images/card_layout.png index b616291..f4b4514 100755 Binary files a/resources/images/card_layout.png and b/resources/images/card_layout.png differ diff --git a/resources/images/civilian.png b/resources/images/civilian.png index 4170786..427d754 100755 Binary files a/resources/images/civilian.png and b/resources/images/civilian.png differ diff --git a/resources/images/collection_background.jpg b/resources/images/collection_background.jpg new file mode 100644 index 0000000..5dff571 Binary files /dev/null and b/resources/images/collection_background.jpg differ diff --git a/resources/images/collection_background.png b/resources/images/collection_background.png deleted file mode 100644 index d9ccf76..0000000 Binary files a/resources/images/collection_background.png and /dev/null differ diff --git a/resources/images/collection_frame.png b/resources/images/collection_frame.png new file mode 100644 index 0000000..3fb6bb6 Binary files /dev/null and b/resources/images/collection_frame.png differ diff --git a/resources/images/credits_background.png b/resources/images/credits_background.png index b616291..ca451ba 100755 Binary files a/resources/images/credits_background.png and b/resources/images/credits_background.png differ diff --git a/resources/images/day_camp.jpg b/resources/images/day_camp.jpg new file mode 100644 index 0000000..d4a83c8 Binary files /dev/null and b/resources/images/day_camp.jpg differ diff --git a/resources/images/day_camp.png b/resources/images/day_camp.png deleted file mode 100644 index 800c1ad..0000000 Binary files a/resources/images/day_camp.png and /dev/null differ diff --git a/resources/images/decision_background.png b/resources/images/decision_background.png index b616291..4e95816 100755 Binary files a/resources/images/decision_background.png and b/resources/images/decision_background.png differ diff --git a/resources/images/decision_choice_background.png b/resources/images/decision_choice_background.png index 3a302a8..83ae364 100755 Binary files a/resources/images/decision_choice_background.png and b/resources/images/decision_choice_background.png differ diff --git a/resources/images/decree_background.png b/resources/images/decree_background.png index 87ae266..8eb7a42 100755 Binary files a/resources/images/decree_background.png and b/resources/images/decree_background.png differ diff --git a/resources/images/decree_choice_background.png b/resources/images/decree_choice_background.png index 87ae266..0a90d82 100755 Binary files a/resources/images/decree_choice_background.png and b/resources/images/decree_choice_background.png differ diff --git a/resources/images/ending_background.png b/resources/images/ending_background.png index 87ae266..cdac0d4 100755 Binary files a/resources/images/ending_background.png and b/resources/images/ending_background.png differ diff --git a/resources/images/ending_civilian_max.jpg b/resources/images/ending_civilian_max.jpg new file mode 100644 index 0000000..3dfce7c Binary files /dev/null and b/resources/images/ending_civilian_max.jpg differ diff --git a/resources/images/ending_civilian_min.jpg b/resources/images/ending_civilian_min.jpg new file mode 100644 index 0000000..1d87dbb Binary files /dev/null and b/resources/images/ending_civilian_min.jpg differ diff --git a/resources/images/ending_food.jpg b/resources/images/ending_food.jpg new file mode 100644 index 0000000..ad344b7 Binary files /dev/null and b/resources/images/ending_food.jpg differ diff --git a/resources/images/ending_military_max.jpg b/resources/images/ending_military_max.jpg new file mode 100644 index 0000000..cf7803e Binary files /dev/null and b/resources/images/ending_military_max.jpg differ diff --git a/resources/images/ending_military_min.jpg b/resources/images/ending_military_min.jpg new file mode 100644 index 0000000..f26d5b5 Binary files /dev/null and b/resources/images/ending_military_min.jpg differ diff --git a/resources/images/ending_order_max.jpg b/resources/images/ending_order_max.jpg new file mode 100644 index 0000000..fa1cf8b Binary files /dev/null and b/resources/images/ending_order_max.jpg differ diff --git a/resources/images/ending_order_max.png b/resources/images/ending_order_max.png deleted file mode 100644 index d9ccf76..0000000 Binary files a/resources/images/ending_order_max.png and /dev/null differ diff --git a/resources/images/ending_order_min.jpg b/resources/images/ending_order_min.jpg new file mode 100644 index 0000000..58c9e52 Binary files /dev/null and b/resources/images/ending_order_min.jpg differ diff --git a/resources/images/ending_paleo_max.jpg b/resources/images/ending_paleo_max.jpg new file mode 100644 index 0000000..c1d9851 Binary files /dev/null and b/resources/images/ending_paleo_max.jpg differ diff --git a/resources/images/ending_paleo_min.jpg b/resources/images/ending_paleo_min.jpg new file mode 100644 index 0000000..d864fbc Binary files /dev/null and b/resources/images/ending_paleo_min.jpg differ diff --git a/resources/images/ending_tools.jpg b/resources/images/ending_tools.jpg new file mode 100644 index 0000000..36370b7 Binary files /dev/null and b/resources/images/ending_tools.jpg differ diff --git a/resources/images/ending_unknown.png b/resources/images/ending_unknown.png index d9ccf76..c04d196 100644 Binary files a/resources/images/ending_unknown.png and b/resources/images/ending_unknown.png differ diff --git a/resources/images/ending_weapons.jpg b/resources/images/ending_weapons.jpg new file mode 100644 index 0000000..40ce33f Binary files /dev/null and b/resources/images/ending_weapons.jpg differ diff --git a/resources/images/event_background.jpg b/resources/images/event_background.jpg new file mode 100644 index 0000000..2a9f87b Binary files /dev/null and b/resources/images/event_background.jpg differ diff --git a/resources/images/event_background.png b/resources/images/event_background.png deleted file mode 100755 index b616291..0000000 Binary files a/resources/images/event_background.png and /dev/null differ diff --git a/resources/images/game_background.png b/resources/images/game_background.png deleted file mode 100755 index d9ccf76..0000000 Binary files a/resources/images/game_background.png and /dev/null differ diff --git a/resources/images/guillotine.png b/resources/images/guillotine.png index 79f826c..835c757 100644 Binary files a/resources/images/guillotine.png and b/resources/images/guillotine.png differ diff --git a/resources/images/menu_background.jpg b/resources/images/menu_background.jpg new file mode 100644 index 0000000..e175caf Binary files /dev/null and b/resources/images/menu_background.jpg differ diff --git a/resources/images/menu_background.png b/resources/images/menu_background.png deleted file mode 100755 index 9671299..0000000 Binary files a/resources/images/menu_background.png and /dev/null differ diff --git a/resources/images/military.png b/resources/images/military.png index 9180d05..0d3f508 100755 Binary files a/resources/images/military.png and b/resources/images/military.png differ diff --git a/resources/images/next_button.png b/resources/images/next_button.png index 9a697da..3f95449 100644 Binary files a/resources/images/next_button.png and b/resources/images/next_button.png differ diff --git a/resources/images/night_camp.jpg b/resources/images/night_camp.jpg new file mode 100644 index 0000000..040a26d Binary files /dev/null and b/resources/images/night_camp.jpg differ diff --git a/resources/images/night_camp.png b/resources/images/night_camp.png deleted file mode 100644 index 355cc87..0000000 Binary files a/resources/images/night_camp.png and /dev/null differ diff --git a/resources/images/order.png b/resources/images/order.png index 97c87fc..69929c8 100755 Binary files a/resources/images/order.png and b/resources/images/order.png differ diff --git a/resources/images/paleo.png b/resources/images/paleo.png index ff2c036..e4b6348 100755 Binary files a/resources/images/paleo.png and b/resources/images/paleo.png differ diff --git a/resources/images/settings_background.jpg b/resources/images/settings_background.jpg new file mode 100644 index 0000000..953e2fa Binary files /dev/null and b/resources/images/settings_background.jpg differ diff --git a/resources/images/settings_logo.png b/resources/images/settings_logo.png new file mode 100644 index 0000000..e0ae51f Binary files /dev/null and b/resources/images/settings_logo.png differ diff --git a/resources/images/tools.png b/resources/images/tools.png index e8fbac2..d157a0d 100755 Binary files a/resources/images/tools.png and b/resources/images/tools.png differ diff --git a/resources/images/tutorial_background.png b/resources/images/tutorial_background.png new file mode 100644 index 0000000..5372d89 Binary files /dev/null and b/resources/images/tutorial_background.png differ diff --git a/resources/images/weapons.png b/resources/images/weapons.png index 7495806..fc1bd1b 100755 Binary files a/resources/images/weapons.png and b/resources/images/weapons.png differ diff --git a/resources/images/wood_background.png b/resources/images/wood_background.png deleted file mode 100755 index 3a302a8..0000000 Binary files a/resources/images/wood_background.png and /dev/null differ diff --git a/resources/languages/english.json b/resources/languages/english.json new file mode 100644 index 0000000..163781c --- /dev/null +++ b/resources/languages/english.json @@ -0,0 +1,396 @@ +{ + "decision": { + "cathedral": { + "text": "Vous vous êtes engagé à lancer le chantier d'une cathédrale auprès de l'Ordre, mais un milicien vous apprend qu'une brèche a été constatée dans les remparts.", + "yes": "La cathédrale attendra.", + "no": "Ces pierres ne nous protégerons pas de Son courroux, pauvres fous !" + }, + "pteranodon_embryo": { + "text": "Un paléontologue vous annonce qu'il a réussi à créer in vitro un embryon de ptéranodon. Il affirme que cela nous permettra de mieux comprendre leurs forces et leurs faiblesses.", + "yes": "Encourageons-le à poursuivre ses recherches.", + "no": "Hérésie ! Brûlons-le avec ses travaux !" + }, + "religious_sacrifice": { + "text": "L’évêque vous informe que les visions des oracles de l'Ordre sont sans appel : nous devons sacrifier treize survivants demain à treize heure.", + "yes": "Qu'il en soit selon la volonté des cieux.", + "no": "Quelques poulets feront bien l'affaire." + }, + "tough_winter": { + "text": "Un ouvrier agricole vous réclame des vivres pour faire face au rude hiver qui s'annonce.", + "yes": "Tenez mon brave.", + "no": "L'État ne peut pas tout." + }, + "weapons_for_military": { + "text": "Le général de la Milice se plaint de l'état déplorable des équipements de ses troupes. Il menace de démissionner si les choses ne s'améliorent pas.", + "yes": "Très bien, très bien, ponctionnez sur les stocks stratégiques !", + "no": "Pour qui vous prenez-vous ?!" + }, + "food_for_dragon": { + "text": "Un représentant de l'Ordre vous demande des viandes et des huiles pour favoriser la venue du Dragon des derniers jours.", + "yes": "Qu'on les lui donne !", + "no": "Donnons-les plutôt au peuple !" + }, + "security_perimeter": { + "text": "Le général de la Milice est effaré des sorties régulières des survivants hors des périmètres de sécurité.", + "yes": "Renforcez les patrouilles et instaurez un couvre-feu !", + "no": "Armons les survivants directement !" + }, + "merchant": { + "text": "Un marchand vous demande de le couvrir auprès de la Milice en échange de vivres et d'outils.", + "yes": "Il est vrai que nous nos coffres sont désespérément vides...", + "no": "Ignorons-le." + }, + "witch": { + "text": "Un survivant s'approche de vous avec une paléontologue ligotée qui a été lynchée par la foule. Le survivant affirme l'avoir aperçue en train d'accoucher d'un reptile cornu. Il vous demande de la condamner à mort.", + "yes": "Libérez cette innocente, pauvre fou !", + "no": "C'est une sorcière, qu'il en soit ainsi." + }, + "tough_labour": { + "text": "Un survivant qui dit travailler à l'atelier de fabrication d'armes vous implore de réduire les cadences de production. Votre regard s'attarde sur ses mains difformes avilies par le labeur.", + "yes": "Silence ! Nous avons besoin de plus d'armes ! Augmentez les cadences !", + "no": "Oui, cela est juste et bon." + }, + "paleo_tools": { + "text": "L'intendant du laboratoire des paléontologues vous apporte un compte-rendu de leurs dépenses en outils. Elles sont anormalement élevées et vous constatez que des armes ont également été consommées.", + "yes": "Ils savent ce qu'ils font.", + "no": "Vous n'aurez rien de plus que d'habitude !" + }, + "black_market": { + "text": "Le commandant de la section \"Ordre public\" de la Milice vous somme de prendre des mesures plus fortes pour faire face à la contrebande de vivres.", + "yes": "Vous avez carte blanche, commandant.", + "no": "Tolérons plutôt ce trafic, beaucoup trop de survivants en dépendent." + }, + "paleo_researches": { + "text": "L’évêque s'indigne des enseignements prodigués par les paléontologues. Il affirme que ces derniers cherchent à embrigader des survivants dans leur quête du culte impie de la Raison.", + "yes": "Emprisonnez-les. La connaissance, c'est le pouvoir !", + "no": "Et alors ?" + }, + "sioux_falls_ruins": { + "text": "Le capitaine d'une brigade d'exploration de la Milice vous fait son rapport. Il prétend avoir découvert un ordinateur d'agronomie dans les ruines de Sioux Falls. Il renferme sans doute de nombreuses connaissances.", + "yes": "Demandez aux paléontologues de le décrypter.", + "no": "Arrière ! Cet objet est porteur du vice qui a amené sur nous les dinosaures !" + }, + "riots": { + "text": "Depuis plusieurs jours des va-nu-pieds s'agglutinent devant votre quartier général pour réclamer des vivres. Certains brûlent vos portraits et portent des banderoles dénonçant l'opulence de l'Ordre.", + "yes": "Donnons-leur des vivres et parlementons avec eux.", + "no": "Que la Milice disperse les émeutiers !" + }, + "party_for_the_dragon": { + "text": "Une comète a été aperçue dans le ciel. Votre aumônier affirme que c'est un signe de la venue prochaine du Dragon des derniers jours, et qu'il nous faut afficher notre foi en lui offrant une grande part de nos ressources.", + "yes": "Faire de l'événement une grande fête populaire.", + "no": "Congédier l'aumônier." + }, + "alamosaurus": { + "text": "Un paléontologue vous informe qu'un nid d'Alamosaurus sanjuanensis a été découvert non loin du campement. Une aubaine pour en savoir plus sur cette sous-espèce ! Mais vos chasseurs préfèrent collecter le bois du nid pour en faire des armes... Hérésie !", + "yes": "Une sous-espèce... intéressant !", + "no": "C'est toi l'hérétique ! Allez prendre ce bois !" + }, + "thief": { + "text": "Un soldat vous annonce qu'un adepte est venu voler des outils destinés à la Milice pour réparer l'autel de l'Église.", + "yes": "Punissez-le !", + "no": "L'autel est plus important !" + }, + "circle_game": { + "text": "Un milicien vous rapporte que des citoyens se sont amusés à faire le jeu du rond aux soldats pour les agacer.", + "yes": "Ce jeu est idiot...", + "no": "Ce jeu est génial !" + }, + "eggs": { + "text": "Un survivant vous informe que des œufs ont été trouvés près du camp. Votre peuple a faim, mais vos paléontologues ont besoin de cet œuf pour l'analyser.", + "yes": "Ce soir, c'est œufs au plat !", + "no": "Pas touche à ces œufs !" + }, + "iron_mine": { + "text": "Un professeur prétend avoir détecté une ancienne mine de fer encore exploitable sous notre campement. Les fanatiques affirment qu'elle renferme un artefact sacré qui causera notre perte si nous y accédons.", + "yes": "De l'acier pour notre survie !", + "no": "Arrière, serviteur du diable !" + }, + "services": { + "text": "L’évêque dénonce l'absence du peuple aux messes organisées pour assurer la croissance de nos plantations.", + "yes": "Messe obligatoire !", + "no": "Prêtres, à vos charrues !" + }, + "snake_soup": { + "text": "Un commerçant affirme que la consommation de serpents fraîchement tués est excellente pour gagner de la vigueur en combat et souhaite en servir une soupe à la Milice.", + "yes": "Enfin un connaisseur !", + "no": "On dit la même chose des fesses de babouin ! Pas de ça chez moi !" + }, + "market": { + "text": "Un démocrate vous demande de créer un grand marché hebdomadaire pour lutter contre le trafic de nourriture.", + "yes": "Vive le capitalisme !", + "no": "J'aime le marché noir." + }, + "religious_songs": { + "text": "Un habitant se plaint des chants religieux trop forts à côté de chez lui.", + "yes": "Qu'on les fasse taire.", + "no": "Qu'on te fasse taire." + }, + "sunglasses": { + "text": "Le général de la Milice demande à ce que l'on fournisse des lunettes de soleil à toute la Milice pour ne pas être ébloui lors des combats contre les dinosaures de plus de trois mètres de haut.", + "yes": "Du confort pour être plus fort !", + "no": "Brûle-toi les yeux pour ton souverain." + }, + "trapped_by_trex": { + "text": "Un paléontologue vous supplie d'aider ses collègues, pris au piège par des tyrannosaures alors qu'ils étudiaient quelques empreintes de chenilles.", + "yes": "Vite ! Leurs travaux doivent être importants !", + "no": "Des imbéciles en moins !" + }, + "conversion": { + "text": "Un habitant se plaint car les religieux se sont mis à venir dans sa tente pour tenter de le convertir.", + "yes": "Stoppez cette pratique !", + "no": "Fais comme tout le monde, accepte-les !" + }, + "bananas": { + "text": "Un soldat vous rapporte qu'une caisse remplie de bananes encore mûres vient d'être déterrée près de l'église.", + "yes": "Un festin pour mes soldats !", + "no": "Rendez-ça aux prêtres ! " + }, + "horses": { + "text": "Un fermier a repéré des chevaux dans une plaine au loin. Ils pourraient aider les miliciens à se déplacer mais les volontaires ne se bousculent pas pour aller les attraper.", + "yes": "Allez me chercher ces chevaux !", + "no": "C'est pas ma priorité vois-tu." + }, + "morphine": { + "text": "Un paléontologue rapporte que les cargaisons de morphine ont été volées par les adeptes.", + "yes": "Ils paieront pour cet affront !", + "no": "Il leur faut au moins ça..." + }, + "therizinosaurus": { + "text": "Un général vous explique qu'il faut abattre la reine des therizinosaurus avant qu'elle ne se reproduise.", + "yes": "Allez-y !", + "no": "Pas touche à la maman !" + }, + "buried_weapons": { + "text": "Un paléontologue a déterré une caisse d'armes lors de ses fouilles.", + "yes": "Je prends.", + "no": "C'est un piège !" + }, + "magic_tools": { + "text": "Un fabricant a inventé un procédé ingénieux permettant de créer des outils, mais il a disparu avoir de l'avoir entièrement finalisé. Une seule utilisation est possible.", + "yes": "C'est mieux que rien.", + "no": "C'est louche." + }, + "monument_for_soldiers": { + "text": "Un sergent demande à ce que l'on érige un monument en hommage aux guerriers disparus.", + "yes": "Nous devons les remercier.", + "no": "De quoi parlez-vous ?" + }, + "fertilizer": { + "text": "Un paléontologue propose d'utiliser les os de diplodocus broyés au niveau des cultures de mais afin d'en augmenter les rendements.", + "yes": "Que ces protocoles soient immédiatement appliqués !", + "no": "Des os de diplodocus ? Vous voulez corrompre notre sol avec cette horreur ?" + }, + "prison": { + "text": "Vous visitez vos geôles et un brigand vous interpelle. Il vous propose de vous livrer le contenu de sa cache d'armes en l'échange de sa liberté.", + "yes": "Il est vrai que nous manquons cruellement d'armes...", + "no": "Je crois que je vais plutôt vous laisser pourrir ici." + }, + "workshop": { + "text": "Un artisan patriote décède et décide de vous léguer son atelier. Il ne vous est d'aucune utilité mais vous pouvez récolter des matériaux en le démantelant.", + "yes": "Conservez-le, il inspirera les générations futures.", + "no": "Démantelez l'atelier." + }, + "parade": { + "text": "Le général de la Milice demande à organiser un défilé militaire chaque année à la gloire de ses soldats.", + "yes": "J'en propose même deux !", + "no": "Très bien mais pas cher ! Pas de folies cette année !" + }, + "weapons_manufacture": { + "text": "Un fabricant d'armes vous explique qu'il peut augmenter sa production si vous acceptez de lui donner quelques guerriers.", + "yes": "Sacrifice facile.", + "no": "Mes soldats valent mieux que ça !" + }, + "dino_carcass": { + "text": "Le directeur des paléontologues veut vous donner les carcasses de dinosaures non utilisées pour nourrir votre camp. Mais il exige des outils en retour.", + "yes": "Merci, tenez vos outils.", + "no": "Je les prends mais vous n'aurez rien." + }, + "tools_food": { + "text": "Une paléontologue a inventé un système rendant les outils plus résistants. Elle demande une prime en vivres pour sa découverte.", + "yes": "Merci, cela mérite bien une prime !", + "no": "Je prends, mais vous n'avez qu'à manger vos outils." + }, + "dino_bile": { + "text": "Un chercheur rapporte que les paléontologues ont extrait des armes de l'estomac d'un diplodocus, mais ils veulent les garder pour pouvoir se défendre.", + "yes": "Très bien, gardez vos armes dégoûtantes.", + "no": "Donnez ces armes à mes guerriers !" + }, + "tools_with_bones": { + "text": "L'une de vos équipes de paléontologues a découvert un nouveau procédé pour rendre plus rigides des os de dinosaures. Ils seraient parfaits pour faire des outils mais votre équipe souhaite continuer les expériences sur les échantillons déjà créés.", + "yes": "Bizarre mais après tout, chacun ses passe-temps.", + "no": "Parfait, je vous les prends, on manquait de bêches !" + }, + "weapons_for_paleo": { + "text": "Le général de la Milice vous rend visite pour vous faire état du nombre infime d'armes restant à la disposition de ses soldats. Il propose que vous réquisitionnez les paléontologues pour supporter l'effort des survivants à créer de nouvelles armes.", + "yes": "Prenez-en vingt, pour une fois qu'ils peuvent se rendre utiles !", + "no": "Revenez me voir quand vous saurez compter jusqu'à vingt !" + }, + "suspect_individual": { + "text": "Un individu suspect vêtu de haillons se présente à vous tout bégayant. L'un de ses amis marchand s'est retrouvé coincé dans une ruine non loin de votre campement par quelques compsognathus affamés. Il vous supplie de lui venir en aide et vous promet que son ami pourra vous donner sa cargaison d'outils.", + "yes": "Ton histoire d'outils a intérêt à être vraie. Qu'on dépêche des soldats pour aider le marchand !", + "no": "Qu'on te fasse taire, toi et tes mensonges !" + } + }, + "answer": { + "yes": { + "order": "L'homme d’église vous adresse sa bénédiction et s’en retourne dans son temple.", + "military": "Le milicien vous salue et quitte les lieux.", + "civilian": "Le survivant s'incline respectueusement et recule en vous regardant jusqu'à atteindre la porte.", + "paleo": "Le paléontologue vous quitte en se frottant les mains, son rire nerveux et ses tics de joie sont on ne peut plus désagréables." + }, + "no": { + "order": "Les traits de l’homme d’église se tendent. Il vous quitte après des salutations bien trop obséquieuses...", + "military": "Le milicien quitte les lieux. Il peine à dissimuler sa frustration. Vous entendez le claquement rageur de ses bottes pendant de longues minutes.", + "civilian": "Le survivant vous quitte en grommelant quelques mots inaudibles. Sans doute des insultes.", + "paleo": "Le paléontologue s'exclame : \"Endomicropachycephalosaurus !\" et s’éloigne. Vous supposez qu'il s'agit d'une insulte." + }, + "guillotine": "Vous regardez les miliciens s’emparer du condamné et le conduire à l’échafaud. Vous entendez le sifflement sinistre de la lame fendre l'air.", + "decree": "Le décret a été appliqué selon votre volonté. Votre suprématie est réaffirmée.", + "event": "À la suite de ces péripéties, vous partez vous coucher en espérant que le jour suivant sera moins mouvementé." + }, + "decree": { + "cocks": { + "text": "Organiser des combats de coqs sur la place centrale." + }, + "missionaries": { + "text": "Envoyer des missionnaires dans les écoles." + }, + "propaganda": { + "text": "Lancer une campagne de propagande en faveur de la Milice." + }, + "researches": { + "text": "Assouplir la réglementation de la recherche." + }, + "obsolete_weapons": { + "text": "Réquisitionner les artisans pour remettre en état des armes obsolètes." + }, + "edible_animals": { + "text": "Introduire de nouvelles espèces dans la liste officielle des animaux comestibles." + }, + "non_essential_infrastructures": { + "text": "Désassembler des infrastructures non-essentielles." + }, + "prayers": { + "text": "Prier le Dragon des derniers jours pour augmenter les rendements agricoles." + }, + "puzzle": { + "text": "Organiser sur la place publique un atelier puzzle géant avec des os de brachiosaures." + } + }, + "event": { + "rain": { + "text": "Il pleut !" + }, + "military_career": { + "text": "De plus en plus de survivants s'engagent dans une carrière militaire, avec l'espoir d'accéder ainsi a davantage de facilités matérielles. Vaine espérance de leur part, mais cela sert vos intérêts." + }, + "wooded_sector": { + "text": "La Milice a fini par sécuriser un secteur arboré aux alentours du campement. Le bois de grande qualité de ce secteur nous permettra de produire un grand nombre d'outils." + }, + "agricultural_machines": { + "text": "Un ingénieur militaire vient de trouver un moyen particulièrement efficace pour transformer des machines agricoles obsolètes en engins d'assaut dévastateurs. La Milice saura en tirer profit lors de ses prochaines expéditions." + }, + "researches_amonites": { + "text": "Les paléontologues sont parvenus à un accord avantageux avec l'évèque. Ce dernier ne s'opposera plus à leurs recherches sur les amonites, en échange de passe-droits plus que douteux. Il vaudrait mieux que les fidèles n'en apprennent rien, mais en attendant, réjouissons-nous des bénéfices à venir de ces recherches." + }, + "storm_fear": { + "text": "Les craintes suscitées par les orages particulièrement violents de ces dernières semaines ont été habilement exploitées par l'Ordre. Les survivants sont désormais convaincus que l'évèque va intercéder en leur faveur pour apaiser la colère du Dragon des derniers jours." + }, + "lottery": { + "text": "Une loterie est organisée par les citoyens pour se changer les idées. Ils trouvent ce jeu particulièrement satisfaisant, ce qui leur remonte le moral." + }, + "carpentry_tools": { + "text": "Eurêka ! Des documents décryptés par nos paléontologues contenaient des patrons d'instruments de menuiserie. Nous allons les mettre à profit pour améliorer l'efficacité de nos constructions." + }, + "fire_church": { + "text": "Une église est en feu ! Non seulement l'origine de cet incendie est vraisemblablement criminelle, mais les survivants risquent de douter de l'efficacité de la protection de monseigneur l'évèque sur le campement." + }, + "oleg": { + "text": "Un homme qui prétend se nommer Oleg et qui viendrait de ce qui était autrefois la Russie est arrive au camp. Nous n'avons pas l'habitude d'accepter des étrangers, mais les stocks d'armes conséquents qu'apporte Oleg faciliteront certainement son intégration en ces temps difficiles." + }, + "dino_cave": { + "text": "Les paléontologues ont découvert une caverne où des dinosaures stockaient toutes leurs ressources ! Ils s'empressent de ramener toutes les vivres au campement." + }, + "dino_attack": { + "text": "Une horde de compsognathus attaque votre campement sans prévenir. Les survivants sont affolés mais la milice parvient à contenir la crise moyennant quelques armes. De nombreux cadavres de ces petites bestioles sont parsemés dans votre camp, pour le plus grand bonheur des paléontologues qui s'empressent d'en subtiliser quelques-uns pour les étudier. Les autres sont utilisés pour regarnir vos réserves de nourriture." + } + }, + "ending": { + "food": { + "title": "TODO", + "text": "Les survivants commencent à faire bouillir leurs chaussures et leurs vêtements pour se nourrir. Votre autorité n'a plus de sens pour ces hommes dont le dénuement nourrit des pulsions révolutionnaires. Ces corps décharnés vous saisissent et vous conduisent dans un immense chaudron sur la place publique. Vos jours s’achèvent en bain-marie. Vous n'obtenez guère mieux que les intestins des survivants pour sépulture." + }, + "tools": { + "title": "TODO", + "text": "Les équipements du camp tombent en ruine et vous ne parvenez pas à les réparer. L'agriculture, les dispositifs de sécurité et la recherche sont paralysés. Vous vous décidez à mener une expédition dans les vestiges des villes alentours afin de récolter des outils et des matériaux. L’évêque profite de votre absence pour prendre le pouvoir et vous êtes attaqué sur le chemin du retour par des vélociraptors. Vous êtes emporté à la tête de l'ultime charge de votre groupe." + }, + "weapons": { + "title": "TODO", + "text": "C'est équipée de frondes et de bâtons que la Milice doit faire face à une énième attaque de tricératops. Les pierres et les boulettes de de papiers rebondissent sur leurs écailles et ces derniers ravagent le campement. Vous terminez piétiné sous une charge dévastatrice du troupeau." + }, + "order_max": { + "title": "TODO", + "text": "Fort de son pouvoir sur la société, l'Ordre ardent du Dragon des derniers jours lance une campagne de purification du campement contre ses opposants. Après avoir massacré les paléontologues et pris le contrôle de la Milice, l'Ordre envoie la foule se saisir de vous. Vos os et votre chair sont consumés sur un bûcher sacrificiel." + }, + "order_min": { + "title": "TODO", + "text": "Alors que le pouvoir de l'Ordre se délite, les survivants privés de l'Espérance du Salut prennent conscience de l’absurdité de l'existence dans un monde qui n'est plus celui des hommes. Ils ne vous obéissent plus et se laissent mourir. Vous êtes désormais le dernier des hommes." + }, + "military_max": { + "title": "TODO", + "text": "La Milice est devenue si puissante que l'on ne sait plus très bien ce qui la contraint à vous obéir. Elle-même se le demande. Vos gardes vous trahissent dans la nuit et la Milice se saisit de vous. Par un petite ouverture dans la toile du camion qui semble vous emmener hors du campement, vous avez le temps d'apercevoir des affiches de propagandes à l'effigie du général de la Milice couvrir les murs de votre ancienne demeure." + }, + "military_min": { + "title": "TODO", + "text": "La poignée d'hommes qui reste dans la Milice n'est guère plus armée que de quelques vieilles armes rouillées quand l'attaque de vélociraptors survient. Vos défenses sont submergées et le campement est rasé de la carte." + }, + "civilian_max": { + "title": "TODO", + "text": "Vous avez été trop tendre et les survivants se sentent pousser des ailes. La foule parvient à rallier la Milice à sa cause pour exiger la fin de votre pouvoir et la mise en place d'une gouvernance démocratique. L’émeute dégénère et les survivants débordent vos positions. Ils s'emparent de vous et vous emmènent vers la guillotine." + }, + "civilian_min": { + "title": "TODO", + "text": "Votre pouvoir n'a jamais semblé aussi fort. Les survivants sont à votre botte et semblent complètement apathiques. Toutefois, vous observez progressivement le campement se dépeupler. Il vous semble que ceux qui restent ne produisent presque plus rien. La poignée d'hommes qui occupe alors le campement ne peut guère vous défendre lors de l'attaque des ptéranodons, et vous périssez entre leurs griffes." + }, + "paleo_max": { + "title": "TODO", + "text": "Les paléontologues, convaincus d'avoir enfin mis au point un appareil permettant de communiquer avec les dinosaures, se décident à en introduire quelques-uns sur le campement. Contre toute attente, l'essai est un échec. Les dinosaures ne sont pas réceptifs aux messages envoyés. Ils se déchaînent sur les survivants et vous périssez entre les mâchoires d'un tyrannosaure." + }, + "paleo_min": { + "title": "TODO", + "text": "L'Ordre ardent du Dragon des derniers jours déchaîne une foule d'adeptes sur ce qui reste du laboratoire des paléontologues. Ses derniers occupants sont lynchés et leurs travaux finissent en autodafé. Sans le recours de la science, la qualité des équipements de la Milice et la productivité agricole déclinent. Ce n'est plus qu'une question de temps avant que vous mourriez de faim ou d'une attaque de dinosaures." + } + }, + "introduction": { + "story": "La civilisation a assisté en silence au retour des dinosaures. Elle a disparu comme elle était apparue. Peu sont ceux qui en gardent un souvenir, et ce n'est guère plus qu'un écho imperceptible. L’Humanité se résume peut-être au campement que vous dirigez dans les grandes plaines du Dakota, non loin de ce qui était autrefois le parc des Badlands.", + "goal": "Vous devrez assurer la cohésion et la survie de cette communauté face à la menace constante des dinosaures. Mais ne vous méprenez pas, votre priorité est de maintenir votre pouvoir, quoiqu'il en coûte. Votre main ne devra pas trembler.", + "order": "L'Ordre ardent du dragon des derniers jours :\n\nDes cendres des cultes de jadis est né l'Ordre ardent du Dragon des derniers jours. Les temps rudes favorisent l'émergence de cultes et celui-ci a acquis un grand pouvoir sur les consciences. Ses membres affirment que l'apparition des dinosaures est un châtiment céleste. L'Ordre appelle par conséquent à la pénitence en attendant la venue du Dragon des derniers jours, qui délivrera l’Humanité du joug des dinosaures. L'Ordre interprétera comme une insulte au Dragon des derniers jours toute tentative profane de régler le problème des dinosaures.", + "military": "La Milice :\n\nLa Milice est constituée des survivants les plus braves. Sa mission est de protéger le campement et ses alentours des incursions des dinosaures. Elle mène également des missions d'exploration dans les vestiges de la civilisation antérieure, au grand désarroi de l'Ordre. La Milice est un formidable outil pour contrôler la population. Mais prenez garde à ce qu'elle ne vous devienne pas trop indispensable...", + "civilian": "Les Survivants :\n\nLes survivants sont les habitants dociles du campement. Ils produisent des vivres, et fabriquent armes et outils. Ils vous renverseront s'ils jugent votre pouvoir trop tyrannique. Vous devrez leur accorder quelques facilites matérielles et faire preuve de justice dans vos jugements pour les contenter. Mais n'oubliez pas : si vous leur accordez trop de pouvoir, ils pourraient être tentés de se passer de vous.", + "paleo": "Les paléontologues :\n\nLes paléontologues s’intéressent de près à l'étude des dinosaures. Ils sont les seuls représentants de ce qui était autrefois \"La Science\". Leurs recherches pourraient vous apporter les connaissances décisives pour mettre un terme à l'oppression des dinosaures, à moins que la soif de connaissance des paléontologues ne les attire trop près du camp...", + "food": "Les vivres :\n\nLes vivres sont nécessaires à l'alimentation de vos survivants. L'Ordre peut également les exiger pour des sacrifices.", + "tools": "Les outils :\n\nLes outils sont l'ensemble des instruments qui permettent à vos survivants de travailler. Ils sont également employés pour les constructions.", + "weapons": "Les armes :\n\nLes armes de toute nature sont absolument essentielles à la Milice. Elle en a besoin pour maintenir l'ordre et protéger le campement des dinosaures." + }, + "tutorial": "To do", + "menu": { + "press_to_start": "Cliquez sur l'écran pour commencer une partie" + }, + "game": { + "decree": "Le conseil d'aujourd'hui se termine tard dans la nuit. Vos conseillers vous ont préparé trois décrets pour améliorer le moral dans le camp.\n\nLequel choisissez-vous d'appliquer ?" + }, + "settings": { + "apply": "Appliquer", + "validate": "Valider", + "music_volume": "Volume de la musique", + "sound_volume": "Volume des bruitages", + "language": "Language", + "tutorial": "Tutorial", + "version": "Version " + }, + "game_over": { + "highscore": "Meilleur score : ", + "score": "Score : ", + "credits": "Jeu original développé par :\n\n- Paul Creusy\n-TODO\n\nRemasterisé par :\n\n- Paul Creusy\n- Agathe Aris" + } +} \ No newline at end of file diff --git a/resources/languages/french.json b/resources/languages/french.json index 949747d..8f42345 100644 --- a/resources/languages/french.json +++ b/resources/languages/french.json @@ -379,7 +379,15 @@ "game": { "decree": "Le conseil d'aujourd'hui se termine tard dans la nuit. Vos conseillers vous ont préparé trois décrets pour améliorer le moral dans le camp.\n\nLequel choisissez-vous d'appliquer ?" }, - "settings": {}, + "settings": { + "apply": "Appliquer", + "validate": "Valider", + "music_volume": "Volume de la musique", + "sound_volume": "Volume des bruitages", + "language": "Langue", + "tutorial": "Tutoriel", + "version": "Version " + }, "game_over": { "highscore": "Meilleur score : ", "score": "Score : ", diff --git a/resources/logo.png b/resources/logo.png new file mode 100644 index 0000000..db67845 Binary files /dev/null and b/resources/logo.png differ diff --git a/resources/logo_roadsign.png b/resources/logo_roadsign.png new file mode 100644 index 0000000..af7218e Binary files /dev/null and b/resources/logo_roadsign.png differ diff --git a/resources/logo_white.png b/resources/logo_white.png new file mode 100644 index 0000000..8556861 Binary files /dev/null and b/resources/logo_white.png differ diff --git a/resources/logo_with_name.png b/resources/logo_with_name.png new file mode 100644 index 0000000..c18ca04 Binary files /dev/null and b/resources/logo_with_name.png differ diff --git a/resources/musics/my_office.mp3 b/resources/musics/my_office.mp3 new file mode 100644 index 0000000..135b7fa Binary files /dev/null and b/resources/musics/my_office.mp3 differ diff --git a/resources/teaser.png b/resources/teaser.png new file mode 100644 index 0000000..b929b1d Binary files /dev/null and b/resources/teaser.png differ diff --git a/screens/achievements.kv b/screens/achievements.kv index 35f305a..70d8150 100644 --- a/screens/achievements.kv +++ b/screens/achievements.kv @@ -1,12 +1,12 @@ #:kivy 2.1.0 -#: import PATH_IMAGES tools.path.PATH_IMAGES +#:import PATH_IMAGES tools.path.PATH_IMAGES #:import TEXT_FONT_COLOR tools.constants.TEXT_FONT_COLOR : ImageWithTextButton: source: PATH_IMAGES + "back_arrow.png" - size_hint: None, 0.1 - pos_hint: {"x":0.025, "top": 0.975} + size_hint: None, 0.15 + pos_hint: {"x":0.025, "top": 1} allow_stretch: True width: self.height release_function: root.go_to_menu @@ -21,6 +21,8 @@ font_name: root.font_name halign: "right" text_size: (root.width,None) + outline_width: 2 + outline_color: (1,1,1,1) RelativeLayout: size_hint: 1, 0.85 diff --git a/screens/achievements.py b/screens/achievements.py index 11ae0cb..ca6aa07 100644 --- a/screens/achievements.py +++ b/screens/achievements.py @@ -6,12 +6,13 @@ ### Imports ### ############### +from functools import partial from kivy.uix.label import Label from kivy.uix.button import Button from kivy.uix.relativelayout import RelativeLayout from kivy.uix.image import Image from kivy.core.window import Window -from kivy.properties import StringProperty +from kivy.properties import StringProperty, NumericProperty from tools.path import ( PATH_TEXT_FONT, PATH_IMAGES @@ -21,7 +22,11 @@ TEXT, TEXT_FONT_COLOR ) -from tools.kivy_tools import ImprovedScreen +from tools import ( + music_mixer, + game +) +from tools.kivy_tools import ImprovedScreen, ImageWithTextButton ################ ### Constant ### @@ -41,67 +46,145 @@ class AchievementsScreen(ImprovedScreen): def __init__(self, **kw): super().__init__( font_name=PATH_TEXT_FONT, - back_image_path=PATH_IMAGES + "collection_background.png", + back_image_path=PATH_IMAGES + "collection_background.jpg", **kw) + self.scroll_view_content = {} my_highscore = StringProperty("") number_cols = 3 spacing = Window.size[0] / 50 padding = [0.05 * Window.size[0], 0, 0.05 * Window.size[0], 0] + image_dimension = NumericProperty() + height_layout = NumericProperty() def on_enter(self, *args): self.ids.my_sv_layout.reset_screen() self.my_highscore = TEXT.game_over["highscore"] + \ str(USER_DATA.highscore) self.on_resize() - self.build_scroll_view() + music_mixer.play("my_office") return super().on_enter(*args) def on_resize(self, *args): + # TODO : la taille de la scroll view ne s'update pas quand on resize donc on ne peut pas voir toutes les icones self.spacing = Window.size[0] / 50 + self.image_dimension = (Window.size[0] - 2 * self.padding[0] - self.spacing * ( + self.number_cols - 1)) / self.number_cols + self.height_layout = self.image_dimension + self.spacing + self.build_scroll_view() return super().on_resize(*args) + # def resize_scrollview(self): + # """ + # Resize the scrollview. + # """ + # self.ids.my_sv_layout.reset_screen() + + # for ending_code in self.scroll_view_content: + # label = self.scroll_view_content[ending_code]["label"] + # image = self.scroll_view_content[ending_code]["image"] + # frame = self.scroll_view_content[ending_code]["frame"] + # label.width = self.image_dimension + # image.width = self.image_dimension + # image.heigth = self.image_dimension + # frame.width = self.image_dimension + # frame.heigth = self.image_dimension + + # relative_layout = RelativeLayout( + # size_hint=(None, None), + # height=self.height_layout, + # width=self.image_dimension + # ) + # relative_layout.add_widget(label) + # relative_layout.add_widget(image) + # relative_layout.add_widget(frame) + + # # Add the layout + # self.ids.my_sv_layout.add_widget(relative_layout) + def go_to_menu(self): """ Go back to the main menu. """ self.manager.current = "menu" + def display_ending(self, ending_code, *args): + """ + Go to the game over menu and display the ending. + """ + if USER_DATA.endings[ending_code]: + game.ending_text = TEXT.ending[ending_code]["text"] + game.score = 0 + game.ending = ending_code + self.manager.current = "game_over" + def build_scroll_view(self): + self.ids.my_sv_layout.reset_screen() - for (code_ending, bool_ending) in USER_DATA.endings.items(): + for (ending_code, bool_ending) in USER_DATA.endings.items(): relative_layout = RelativeLayout( - size_hint=(1, 1), - # height=height_layout, - # width=self.image_dimension + size_hint=(None, None), + height=self.height_layout, + width=self.image_dimension ) path_image = PATH_IMAGES + "ending_unknown.png" title_ending = "???" if bool_ending: - path_image = PATH_IMAGES + "ending_" + code_ending + ".png" - title_ending = TEXT.ending[code_ending]["title"] + path_image = PATH_IMAGES + "ending_" + ending_code + ".jpg" + title_ending = TEXT.ending[ending_code]["title"] - name_label = Button( - # width=self.image_dimension, - size_hint=(1, 0.1), + label = Button( + width=self.image_dimension, + size_hint=(0.8, 0.1), # color=TEXT_FONT_COLOR, text=title_ending, - pos_hint={"x": 0, "y": 0}, + pos_hint={"center_x": 0.5, "y": 0}, + on_release=partial(self.display_ending, ending_code) # font_name=self.font_name, # font_size=25 * self.font_ratio ) - relative_layout.add_widget(name_label) + relative_layout.add_widget(label) # Image image = Image( source=path_image, - size_hint=(1, 0.9), - # width=self.image_dimension, - # height=self.image_dimension, + size_hint=(0.7, 0.7), + width=self.image_dimension, + height=self.image_dimension, allow_stretch=True, keep_ratio=False, - pos_hint={"x": 0, "y": 0.1} + pos_hint={"center_x": 0.5, "center_y": 0.5} ) relative_layout.add_widget(image) + + # Frame + frame = Image( + source=PATH_IMAGES + "collection_frame.png", + size_hint=(0.8, 0.8), + width=self.image_dimension, + height=self.image_dimension, + allow_stretch=True, + keep_ratio=False, + pos_hint={"center_x": 0.5, "center_y": 0.5}, + ) + relative_layout.add_widget(frame) + + frame_button = Button( + on_release=partial(self.display_ending, ending_code), + size_hint=(0.8, 0.8), + width=self.image_dimension, + height=self.image_dimension, + pos_hint={"center_x": 0.5, "center_y": 0.5}, + opacity=0 + ) + relative_layout.add_widget(frame_button) + + # Add the layout self.ids.my_sv_layout.add_widget(relative_layout) + + # Store the widgets + self.scroll_view_content[ending_code] = {} + self.scroll_view_content[ending_code]["label"] = label + self.scroll_view_content[ending_code]["image"] = image + self.scroll_view_content[ending_code]["frame"] = frame diff --git a/screens/game.kv b/screens/game.kv index f9800f9..ba5b220 100644 --- a/screens/game.kv +++ b/screens/game.kv @@ -3,20 +3,21 @@ #:import PATH_TEXT_FONT tools.path.PATH_TEXT_FONT #:import TEXT_FONT_COLOR tools.constants.TEXT_FONT_COLOR #:import partial functools.partial -#:set center_x_faction 0.11 +#:set center_x_faction 0.1 #:set center_x_resource 0.93 -#:set upper_y_indic 0.93 +#:set horizontal_shift 0.01 +#:set upper_y_indic 0.92 #:set vertical_spacing_indic 0.09 #:set label_image_spacing 0.05 #:set image_size_indic 0.08 -#:set center_img_height 0.45 +#:set center_img_height 0.5 #:set center_img_width 0.5 #:set center_img_center_y 0.7 #:set side_img_width 0.3 #:set side_img_height 0.2 #:set side_img_center_x 0.175 #:set side_img_center_y 0.25 -#:set text_filling_ratio 0.9 +#:set text_filling_ratio 0.85 #:set sign_offset 0.035 #:set plus_minus_ratio 1/2.5 @@ -30,8 +31,8 @@ Image: id: order_image source: PATH_IMAGES + "card_layout.png" - size_hint: 0.17, vertical_spacing_indic*4.6 - pos_hint: {"center_x": center_x_faction - label_image_spacing*0.45, "center_y": 0.79} + size_hint: 0.15, vertical_spacing_indic*4.6 + pos_hint: {"center_x": center_x_faction - label_image_spacing*0.45, "center_y": 0.785} allow_stretch: True keep_ratio:False @@ -39,56 +40,56 @@ Image: id: plus_order source: PATH_IMAGES + "plus.png" - pos_hint: {"center_x": center_x_faction + sign_offset, "center_y": upper_y_indic} + pos_hint: {"center_x": center_x_faction + sign_offset - horizontal_shift, "center_y": upper_y_indic} size_hint: None, image_size_indic * plus_minus_ratio allow_stretch: True width: self.height Image: id: minus_order source: PATH_IMAGES + "minus.png" - pos_hint: {"center_x": center_x_faction + sign_offset, "center_y": upper_y_indic} + pos_hint: {"center_x": center_x_faction + sign_offset - horizontal_shift, "center_y": upper_y_indic} size_hint: None, image_size_indic * plus_minus_ratio allow_stretch: True width: self.height Image: id: plus_military source: PATH_IMAGES + "plus.png" - pos_hint: {"center_x": center_x_faction + sign_offset, "center_y": upper_y_indic- vertical_spacing_indic*1} + pos_hint: {"center_x": center_x_faction + sign_offset - horizontal_shift, "center_y": upper_y_indic- vertical_spacing_indic*1} size_hint: None, image_size_indic * plus_minus_ratio allow_stretch: True width: self.height Image: id: minus_military source: PATH_IMAGES + "minus.png" - pos_hint: {"center_x": center_x_faction + sign_offset, "center_y": upper_y_indic- vertical_spacing_indic*1} + pos_hint: {"center_x": center_x_faction + sign_offset - horizontal_shift, "center_y": upper_y_indic- vertical_spacing_indic*1} size_hint: None, image_size_indic * plus_minus_ratio allow_stretch: True width: self.height Image: id: plus_civilian source: PATH_IMAGES + "plus.png" - pos_hint: {"center_x": center_x_faction + sign_offset, "center_y": upper_y_indic- vertical_spacing_indic*2} + pos_hint: {"center_x": center_x_faction + sign_offset - horizontal_shift, "center_y": upper_y_indic- vertical_spacing_indic*2} size_hint: None, image_size_indic * plus_minus_ratio allow_stretch: True width: self.height Image: id: minus_civilian source: PATH_IMAGES + "minus.png" - pos_hint: {"center_x": center_x_faction + sign_offset, "center_y": upper_y_indic- vertical_spacing_indic*2} + pos_hint: {"center_x": center_x_faction + sign_offset - horizontal_shift, "center_y": upper_y_indic- vertical_spacing_indic*2} size_hint: None, image_size_indic * plus_minus_ratio allow_stretch: True width: self.height Image: id: plus_paleo source: PATH_IMAGES + "plus.png" - pos_hint: {"center_x": center_x_faction + sign_offset, "center_y": upper_y_indic- vertical_spacing_indic*3} + pos_hint: {"center_x": center_x_faction + sign_offset - horizontal_shift, "center_y": upper_y_indic- vertical_spacing_indic*3} size_hint: None, image_size_indic * plus_minus_ratio allow_stretch: True width: self.height Image: id: minus_paleo source: PATH_IMAGES + "minus.png" - pos_hint: {"center_x": center_x_faction + sign_offset, "center_y": upper_y_indic- vertical_spacing_indic*3} + pos_hint: {"center_x": center_x_faction + sign_offset - horizontal_shift, "center_y": upper_y_indic- vertical_spacing_indic*3} size_hint: None, image_size_indic * plus_minus_ratio allow_stretch: True width: self.height @@ -97,7 +98,7 @@ IndicatorLabel: id: order_label text: root.order_value - pos_hint: {"center_x": center_x_faction, "center_y": upper_y_indic} + pos_hint: {"center_x": center_x_faction - horizontal_shift, "center_y": upper_y_indic} font_size: 20*root.font_ratio font_name: root.font_name color: TEXT_FONT_COLOR @@ -105,13 +106,13 @@ id: order_image source: PATH_IMAGES + "order.png" size_hint: None, image_size_indic - pos_hint: {"center_x": center_x_faction - label_image_spacing, "center_y": upper_y_indic} + pos_hint: {"center_x": center_x_faction - label_image_spacing - horizontal_shift, "center_y": upper_y_indic} allow_stretch: True width: self.height IndicatorLabel: id: military_label text: root.military_value - pos_hint: {"center_x": center_x_faction, "center_y": upper_y_indic - vertical_spacing_indic*1} + pos_hint: {"center_x": center_x_faction - horizontal_shift, "center_y": upper_y_indic - vertical_spacing_indic*1} font_size: 20*root.font_ratio font_name: root.font_name color: TEXT_FONT_COLOR @@ -119,13 +120,13 @@ id: military_image source: PATH_IMAGES + "military.png" size_hint: None, image_size_indic - pos_hint: {"center_x": center_x_faction - label_image_spacing, "center_y": upper_y_indic - vertical_spacing_indic*1} + pos_hint: {"center_x": center_x_faction - label_image_spacing - horizontal_shift, "center_y": upper_y_indic - vertical_spacing_indic*1} allow_stretch: True width: self.height IndicatorLabel: id: civilian_label text: root.civilian_value - pos_hint: {"center_x": center_x_faction, "center_y": upper_y_indic - vertical_spacing_indic*2} + pos_hint: {"center_x": center_x_faction - horizontal_shift, "center_y": upper_y_indic - vertical_spacing_indic*2} font_size: 20*root.font_ratio font_name: root.font_name color: TEXT_FONT_COLOR @@ -133,13 +134,13 @@ id: civilian_image source: PATH_IMAGES + "civilian.png" size_hint: None, image_size_indic - pos_hint: {"center_x": center_x_faction - label_image_spacing, "center_y": upper_y_indic - vertical_spacing_indic*2} + pos_hint: {"center_x": center_x_faction - label_image_spacing - horizontal_shift, "center_y": upper_y_indic - vertical_spacing_indic*2} allow_stretch: True width: self.height IndicatorLabel: id: paleo_label text: root.paleo_value - pos_hint: {"center_x": center_x_faction, "center_y": upper_y_indic - vertical_spacing_indic*3} + pos_hint: {"center_x": center_x_faction - horizontal_shift, "center_y": upper_y_indic - vertical_spacing_indic*3} font_size: 20*root.font_ratio font_name: root.font_name color: TEXT_FONT_COLOR @@ -147,7 +148,7 @@ id: paleo_image source: PATH_IMAGES + "paleo.png" size_hint: None, image_size_indic - pos_hint: {"center_x": center_x_faction - label_image_spacing, "center_y": upper_y_indic - vertical_spacing_indic*3} + pos_hint: {"center_x": center_x_faction - label_image_spacing - horizontal_shift, "center_y": upper_y_indic - vertical_spacing_indic*3} allow_stretch: True width: self.height @@ -155,8 +156,8 @@ Image: id: resources_background source: PATH_IMAGES + "card_layout.png" - size_hint: 0.16, vertical_spacing_indic*3.6 - pos_hint: {"center_x": center_x_resource - label_image_spacing*0.45, "center_y": 0.84} + size_hint: 0.15, vertical_spacing_indic*3.6 + pos_hint: {"center_x": center_x_resource - label_image_spacing*0.45, "center_y": 0.83} allow_stretch: True keep_ratio:False @@ -164,42 +165,42 @@ Image: id: plus_food source: PATH_IMAGES + "plus.png" - pos_hint: {"center_x": center_x_resource + sign_offset, "center_y": upper_y_indic} + pos_hint: {"center_x": center_x_resource + sign_offset - horizontal_shift, "center_y": upper_y_indic} size_hint: None, image_size_indic * plus_minus_ratio allow_stretch: True width: self.height Image: id: minus_food source: PATH_IMAGES + "minus.png" - pos_hint: {"center_x": center_x_resource + sign_offset, "center_y": upper_y_indic} + pos_hint: {"center_x": center_x_resource + sign_offset - horizontal_shift, "center_y": upper_y_indic} size_hint: None, image_size_indic * plus_minus_ratio allow_stretch: True width: self.height Image: id: plus_weapons source: PATH_IMAGES + "plus.png" - pos_hint: {"center_x": center_x_resource + sign_offset, "center_y": upper_y_indic - 1* vertical_spacing_indic} + pos_hint: {"center_x": center_x_resource + sign_offset - horizontal_shift, "center_y": upper_y_indic - 1* vertical_spacing_indic} size_hint: None, image_size_indic * plus_minus_ratio allow_stretch: True width: self.height Image: id: minus_weapons source: PATH_IMAGES + "minus.png" - pos_hint: {"center_x": center_x_resource + sign_offset, "center_y": upper_y_indic - 1* vertical_spacing_indic} + pos_hint: {"center_x": center_x_resource + sign_offset - horizontal_shift, "center_y": upper_y_indic - 1* vertical_spacing_indic} size_hint: None, image_size_indic * plus_minus_ratio allow_stretch: True width: self.height Image: id: plus_tools source: PATH_IMAGES + "plus.png" - pos_hint: {"center_x": center_x_resource + sign_offset, "center_y": upper_y_indic - 2* vertical_spacing_indic} + pos_hint: {"center_x": center_x_resource + sign_offset - horizontal_shift, "center_y": upper_y_indic - 2* vertical_spacing_indic} size_hint: None, image_size_indic * plus_minus_ratio allow_stretch: True width: self.height Image: id: minus_tools source: PATH_IMAGES + "minus.png" - pos_hint: {"center_x": center_x_resource + sign_offset, "center_y": upper_y_indic - 2* vertical_spacing_indic} + pos_hint: {"center_x": center_x_resource + sign_offset - horizontal_shift, "center_y": upper_y_indic - 2* vertical_spacing_indic} size_hint: None, image_size_indic * plus_minus_ratio allow_stretch: True width: self.height @@ -208,7 +209,7 @@ IndicatorLabel: id: food_label text: root.food_value - pos_hint: {"center_x": center_x_resource, "center_y": upper_y_indic} + pos_hint: {"center_x": center_x_resource - horizontal_shift, "center_y": upper_y_indic} font_size: 20*root.font_ratio font_name: root.font_name color: TEXT_FONT_COLOR @@ -216,13 +217,13 @@ id: food_image source: PATH_IMAGES + "food.png" size_hint: None, image_size_indic - pos_hint: {"center_x": center_x_resource - label_image_spacing, "center_y": upper_y_indic} + pos_hint: {"center_x": center_x_resource - label_image_spacing - horizontal_shift, "center_y": upper_y_indic} allow_stretch: True width: self.height IndicatorLabel: id: weapons_label text: root.weapons_value - pos_hint: {"center_x": center_x_resource, "center_y": upper_y_indic -vertical_spacing_indic*1} + pos_hint: {"center_x": center_x_resource - horizontal_shift, "center_y": upper_y_indic -vertical_spacing_indic*1} font_size: 20*root.font_ratio font_name: root.font_name color: TEXT_FONT_COLOR @@ -230,13 +231,13 @@ id: weapons_image source: PATH_IMAGES + "weapons.png" size_hint: None, image_size_indic - pos_hint: {"center_x": center_x_resource - label_image_spacing, "center_y": upper_y_indic -vertical_spacing_indic*1} + pos_hint: {"center_x": center_x_resource - label_image_spacing - horizontal_shift, "center_y": upper_y_indic -vertical_spacing_indic*1} allow_stretch: True width: self.height IndicatorLabel: id: tools_label text: root.tools_value - pos_hint: {"center_x": center_x_resource, "center_y": upper_y_indic -vertical_spacing_indic*2} + pos_hint: {"center_x": center_x_resource - horizontal_shift, "center_y": upper_y_indic -vertical_spacing_indic*2} font_size: 20*root.font_ratio font_name: root.font_name color: TEXT_FONT_COLOR @@ -244,7 +245,7 @@ id: tools_image source: PATH_IMAGES + "tools.png" size_hint: None, image_size_indic - pos_hint: {"center_x": center_x_resource - label_image_spacing, "center_y": upper_y_indic -vertical_spacing_indic*2} + pos_hint: {"center_x": center_x_resource - label_image_spacing - horizontal_shift, "center_y": upper_y_indic -vertical_spacing_indic*2} allow_stretch: True width: self.height @@ -270,6 +271,7 @@ text_font_name: root.font_name text_color: TEXT_FONT_COLOR release_function: partial(root.choose_answer, "left") + text_filling_ratio: text_filling_ratio # Decision right ImageWithTextButton: @@ -282,6 +284,7 @@ text_font_name: root.font_name text_color: TEXT_FONT_COLOR release_function: partial(root.choose_answer, "right") + text_filling_ratio: text_filling_ratio # Decision guillotine ImageWithTextButton: @@ -297,7 +300,7 @@ # Event background ImageWithTextButton: id: event - source: PATH_IMAGES + "event_background.png" + source: PATH_IMAGES + "event_background.jpg" size_hint: center_img_width, center_img_height pos_hint: {"center_x": 0.5, "center_y": center_img_center_y} allow_stretch: True @@ -355,7 +358,7 @@ # Answer ImageWithText: id: answer - source: PATH_IMAGES + "answer_background.png" + source: PATH_IMAGES + "answer_background.jpg" size_hint: center_img_width, center_img_height pos_hint: {"center_x": 0.5, "center_y": center_img_center_y} allow_stretch: True @@ -371,4 +374,14 @@ pos_hint: {"center_x": 0.5, "center_y": 0.15} allow_stretch: True keep_ratio: True - release_function: root.go_to_next_card \ No newline at end of file + release_function: root.go_to_next_card + + # # Rewind button + # ImageWithTextButton: + # id: rewind_button + # source: PATH_IMAGES + "rewind_button.png" + # size_hint: 0.1, None + # pos_hint: {"center_x": 0.9, "center_y": 0.5} + # allow_stretch: True + # keep_ratio: True + # release_function: root.rewind \ No newline at end of file diff --git a/screens/game.py b/screens/game.py index 58b6dda..50279e4 100644 --- a/screens/game.py +++ b/screens/game.py @@ -14,7 +14,7 @@ from kivy.lang import Builder from kivy.clock import Clock -from kivy.properties import StringProperty +from kivy.properties import StringProperty, NumericProperty from kivy.loader import Loader, ProxyImage ### Module imports ### @@ -22,16 +22,25 @@ from tools.path import ( PATH_TEXT_FONT, PATH_IMAGES, - PATH_SCREENS + PATH_MUSICS, + PATH_SOUNDS ) from tools import ( music_mixer, sound_mixer, game, + USER_DATA ) from tools.kivy_tools import ( ImprovedScreen ) +from tools.game_tools import ( + load_sounds +) +from tools.constants import ( + MUSIC_LIST, + SOUND_LIST +) ############# @@ -55,12 +64,14 @@ class GameScreen(ImprovedScreen): weapons_value = StringProperty("0") tools_value = StringProperty("0") + # font_size_expand = NumericProperty(1.25) + # Boolean indicating if the current moment is an answer or not is_answer = False def __init__(self, **kw): super().__init__( - back_image_path=PATH_IMAGES + "day_camp.png", + back_image_path=PATH_IMAGES + "day_camp.jpg", font_name=PATH_TEXT_FONT, ** kw) @@ -98,18 +109,26 @@ def __init__(self, **kw): def preload(self, *_): - # Load the kv content - # Builder.load_file(PATH_SCREENS + "game.kv", encoding="utf-8") + if not self.is_loaded: - # Load the night camp background - self.night_camp_background = Loader.image( - PATH_IMAGES + "night_camp.png") + # Load the night camp background + self.night_camp_background = Loader.image( + PATH_IMAGES + "night_camp.jpg") - self.day_camp_background = Loader.image( - PATH_IMAGES + "day_camp.png") + # Load the day camp background + self.day_camp_background = Loader.image( + PATH_IMAGES + "day_camp.jpg") - # Preload the class - super().preload() + # Load the musics and sounds + new_musics = load_sounds( + MUSIC_LIST, PATH_MUSICS, USER_DATA.music_volume) + new_sounds = load_sounds(SOUND_LIST, PATH_SOUNDS, + USER_DATA.sound_effects_volume) + music_mixer.add_sounds(new_musics) + sound_mixer.add_sounds(new_sounds) + + # Preload the class + super().preload() def hide_cards(self, *_): """ @@ -283,3 +302,6 @@ def start_day(self, *_): else: self.update_display_resources() self.manager.current = "game_over" + + def rewind(self): + pass diff --git a/screens/game_over.kv b/screens/game_over.kv index 09db78d..01ca1cc 100644 --- a/screens/game_over.kv +++ b/screens/game_over.kv @@ -7,7 +7,7 @@ # Game Over Label Label: id: game_over_label - text: "Game Over" + text: root.title_text size_hint: 1, 0.5 pos_hint: {"center_x": 0.5, "center_y": 0.9} font_size: 50*root.font_ratio @@ -21,9 +21,9 @@ id: back_button source: PATH_IMAGES + "back_arrow.png" size_hint: None, 0.15 - pos_hint: {"x": 0.05, "y": 0.05} + pos_hint: {"x":0.025, "top": 1} allow_stretch: True - keep_ratio: True + width: self.height release_function: root.back_to_menu # Score diff --git a/screens/game_over.py b/screens/game_over.py index 213976c..6d368fc 100644 --- a/screens/game_over.py +++ b/screens/game_over.py @@ -27,10 +27,11 @@ class GameOverScreen(ImprovedScreen): ending_text = StringProperty() credits_text = StringProperty() score_text = StringProperty() + title_text = StringProperty() def __init__(self, **kw): super().__init__( - back_image_path=PATH_IMAGES + "game_over_background.png", + # back_image_path=PATH_IMAGES + "game_over_background.png", font_name=PATH_TEXT_FONT, **kw) self.credits_text = TEXT.game_over["credits"] @@ -39,6 +40,9 @@ def on_enter(self, *args): music_mixer.play("time_of_the_apocalypse") self.ending_text = game.ending_text + self.set_back_image_path( + PATH_IMAGES + "ending_" + game.ending + ".jpg") + if game.score > USER_DATA.highscore: new_highscore = True USER_DATA.highscore = game.score @@ -48,6 +52,15 @@ def on_enter(self, *args): self.score_text = TEXT.game_over["score"] + str(game.score) + \ TEXT.game_over["highscore"] + str(USER_DATA.highscore) + if game.score == 0: + self.ids["score_label"].opacity = 0 + self.back_destination = "achievements" + self.title_text = TEXT.ending[game.ending]["title"] + else: + self.ids["score_label"].opacity = 1 + self.back_destination = "menu" + self.title_text = "Game Over" + # Display something when getting a new highscore return super().on_enter(*args) @@ -55,4 +68,4 @@ def back_to_menu(self): """ Go back to the main menu """ - self.manager.current = "menu" + self.manager.current = self.back_destination diff --git a/screens/menu.kv b/screens/menu.kv index 371e114..a990007 100644 --- a/screens/menu.kv +++ b/screens/menu.kv @@ -2,26 +2,37 @@ #: import PATH_IMAGES tools.path.PATH_IMAGES #: import TITLE_FONT_COLOR tools.constants.TITLE_FONT_COLOR #: import MOBILE_MODE tools.constants.MOBILE_MODE +#:set side_logo_size 0.2 : Label: + # canvas.before: + # Color: + # rgba: (1,1,1,1) + # Rectangle: + # size: self.size + # pos: self.pos id: title_label text: "Postrias" - size_hint: 1, 0.5 + size_hint: 0.5, 0.2 pos_hint: {"center_x": 0.5, "center_y": 0.85} - font_size: 60*root.font_ratio + font_size: 80*root.font_ratio font_name: root.font_name color: TITLE_FONT_COLOR + outline_width: 2 + outline_color: (1,1,1,1) Label: id: start_label text: "Start a new game" if MOBILE_MODE else "Click to start a new game" size_hint: 1, 0.25 pos_hint: {"center_x": 0.5, "center_y": 0.45} - font_size: 40*root.font_ratio + font_size: 50*root.font_ratio font_name: root.font_name color: TITLE_FONT_COLOR + outline_width: 2 + outline_color: (1,1,1,1) Button: size_hint: 1, 0.25 pos_hint: {"center_x": 0.5, "center_y": 0.45} @@ -32,13 +43,13 @@ Image: id: settings_logo source: PATH_IMAGES + "settings_logo.png" - size_hint: None, 0.15 + size_hint: None, side_logo_size pos_hint: {"right": 0.95, "y": 0.05} allow_stretch: True width: self.height Button: id: settings_button - size_hint: None, 0.15 + size_hint: None, side_logo_size pos_hint: {"right": 0.95, "y": 0.05} background_color: (0, 0, 0, 0) width: self.height @@ -57,12 +68,12 @@ Image: source: PATH_IMAGES + "achievements_logo.png" - size_hint: None, 0.15 + size_hint: None, side_logo_size pos_hint: {"x": 0.05, "y": 0.05} allow_stretch: True width: self.height Button: - size_hint: None, 0.15 + size_hint: None,side_logo_size pos_hint: {"x": 0.05, "y": 0.05} background_color: (0, 0, 0, 0) width: self.height diff --git a/screens/menu.py b/screens/menu.py index 3894ae4..667ad27 100644 --- a/screens/menu.py +++ b/screens/menu.py @@ -26,7 +26,7 @@ class MenuScreen(ImprovedScreen): def __init__(self, **kw): super().__init__( - back_image_path=PATH_IMAGES + "menu_background.png", + back_image_path=PATH_IMAGES + "menu_background.jpg", font_name=PATH_TITLE_FONT, **kw) self.opacity_state = -1 @@ -34,7 +34,8 @@ def __init__(self, **kw): def on_enter(self, *args): # Launch the title music - music_mixer.play("cinematic_dramatic", loop=True) + if music_mixer.musics["cinematic_dramatic"].state == "stop": + music_mixer.play("cinematic_dramatic", loop=True) # Schedule the update for the text opacity effect Clock.schedule_interval(self.update, 1 / FPS) @@ -46,7 +47,8 @@ def on_enter(self, *args): def on_pre_leave(self, *args): # Stop the title music - music_mixer.stop() + if self.manager.current != "settings": + music_mixer.stop() # Unschedule the clock update Clock.unschedule(self.update, 1 / FPS) diff --git a/screens/settings.kv b/screens/settings.kv index a3bb7c7..35ab5c3 100644 --- a/screens/settings.kv +++ b/screens/settings.kv @@ -1,140 +1,117 @@ #:kivy 2.1.0 +#:import PATH_IMAGES tools.path.PATH_IMAGES +#:import TEXT_FONT_COLOR tools.constants.TEXT_FONT_COLOR +#:import TEXT tools.constants.TEXT +#:import LANGUAGES_LIST tools.constants.LANGUAGES_LIST : - # Image: - # id: back_image - # source: root.path_back_image - # size_hint: None,None - # width: root.width_back_image - # height: root.height_back_image - # pos_hint: {"center_x":0.5,"center_y":0.5} - # allow_stretch: True - # keep_ratio: True - - # Image: - # source: root.path_images + "back_arrow.png" - # size_hint: None, 0.1 - # pos_hint: {"x":0.025, "top": 0.975} - # allow_stretch: True - # width: self.height - # Button: - # size_hint: None, 0.1 - # width: self.height - # pos_hint: {"x":0.025, "top": 0.975} - # background_color: (0, 0, 0, 0) - # on_release: - # root.manager.init_screen("menu") + # Back arrow + ImageWithTextButton: + source: PATH_IMAGES + "back_arrow.png" + size_hint: None, 0.15 + pos_hint: {"x":0.025, "top": 1} + allow_stretch: True + width: self.height + release_function: root.go_to_menu - # Label: - # text: root.high_score - # bold: True - # color: root.manager.color_label - # pos_hint: {"right":1, "top":1} - # size_hint: 0.2, 0.1 - # font_name: root.font - # font_size: 30*root.font_ratio + Slider: + id: sound_slider + min: 0 + max: 1 + value: root.sound_volume_value + pos_hint: {"center_x":0.75, "center_y": 0.5} + size_hint: 0.3, 0.1 + Label: + text: root.sound_volume_label + pos_hint: {"center_x":0.75, "center_y": 0.55} + font_size: 25*root.font_ratio + color: TEXT_FONT_COLOR + outline_width: 2 + outline_color: (1,1,1,1) - # # KEYBOARD CONFIGURATION + Slider: + id: music_slider + min: 0 + max: 1 + value: root.music_volume_value + pos_hint: {"center_x":0.75, "center_y": 0.7} + size_hint: 0.3, 0.1 - # Button: - # id: top_button - # text: "Move up" - # size_hint: 0.15, 0.1 - # pos_hint: {"x":0.45, "y":0.7} - # color: root.manager.gray_color - # font_name: root.font - # font_size: 20*root.font_ratio - # on_release: - # root.select_next_key("top") - # Button: - # id: top_key_input - # text: root.top_key - # size_hint: 0.1, 0.1 - # pos_hint: {"x":0.65, "y": 0.7} - # disabled: True - # font_name: root.font - # font_size: 20*root.font_ratio - # color: root.manager.color_label + Label: + text: root.music_volume_label + pos_hint: {"center_x":0.75, "center_y": 0.75} + font_size: 25*root.font_ratio + color: TEXT_FONT_COLOR + outline_width: 2 + outline_color: (1,1,1,1) - # Button: - # id: left_button - # text: "Move left" - # size_hint: 0.15, 0.1 - # pos_hint: {"x":0.45, "y":0.55} - # color: root.manager.gray_color - # font_size: 20*root.font_ratio - # font_name: root.font - # on_release: - # root.select_next_key("left") - # Button: - # id: left_key_input - # text: root.left_key - # size_hint: 0.1, 0.1 - # pos_hint: {"x":0.65, "y": 0.55} - # disabled: True - # font_name: root.font - # font_size: 20*root.font_ratio - # color: root.manager.color_label + Button: + id: apply_music_settings_button + text: root.apply_label + pos_hint: {"center_x":0.75, "center_y": 0.325} + size_hint: 0.3, 0.1 + font_size: 20*root.font_ratio + on_release: + root.apply_music_settings() - # Button: - # id: bottom_button - # text: "Move down" - # size_hint: 0.15, 0.1 - # pos_hint: {"x":0.45, "y":0.4} - # color: root.manager.gray_color - # font_size: 20*root.font_ratio - # font_name: root.font - # on_release: - # root.select_next_key("bottom") - # Button: - # id: bottom_key_input - # text: root.bottom_key - # size_hint: 0.1, 0.1 - # pos_hint: {"x":0.65, "y": 0.4} - # disabled: True - # font_name: root.font - # font_size: 20*root.font_ratio - # color: root.manager.color_label + ### Language ### + Label: + text: root.language_label + pos_hint: {"center_x":0.25, "center_y": 0.75} + font_size: 25*root.font_ratio + color: TEXT_FONT_COLOR + outline_width: 2 + outline_color: (1,1,1,1) + FocusableSpinner: + id: language_spinner + text: root.current_language + pos_hint: {"center_x":0.25, "center_y": 0.65} + size_hint: 0.3, 0.1 + font_size: 20*root.font_ratio + values: root.values_language_list + on_text: + root.change_language(self.text) + ### Tutorial ### + Button: + id: watch_tutorial + text: root.tutorial_label + pos_hint: {"center_x":0.25, "center_y": 0.325} + size_hint: 0.3, 0.1 + font_size: 20*root.font_ratio + on_release: + root.watch_tutorial() - # Button: - # id: right_button - # text: "Move right" - # size_hint: 0.15, 0.1 - # pos_hint: {"x":0.45, "y":0.25} - # color: root.manager.gray_color - # font_size: 20*root.font_ratio - # font_name: root.font - # on_release: - # root.select_next_key("right") - # Button: - # id: right_key_input - # text: root.right_key - # size_hint: 0.1, 0.1 - # disabled: True - # font_name: root.font - # font_size: 20*root.font_ratio - # pos_hint: {"x":0.65, "y": 0.25} - # color: root.manager.color_label + ### Version ### + Label: + text: root.version_label + pos_hint: {"center_x":0.5, "center_y": 0.05} + font_size: 15*root.font_ratio + color: TEXT_FONT_COLOR + outline_width: 2 + outline_color: (1,1,1,1) - # Button: - # id: interact_button - # text: "Interact" - # size_hint: 0.15, 0.1 - # pos_hint: {"x":0.45, "y":0.1} - # color: root.manager.gray_color + # ### Ads ### + # Label: + # text: root.disable_ads_label + # pos_hint: {"center_x":0.25, "center_y": 0.45} + # font_size: 25*root.font_ratio + # color: TEXT_FONT_COLOR + # outline_width: 2 + # outline_color: (1,1,1,1) + + # TextInput: + # id: code_input + # hint_text: root.enter_code_label + # pos_hint: {"center_x":0.25, "center_y": 0.35} + # size_hint: 0.3, 0.1 # font_size: 20*root.font_ratio - # font_name: root.font - # on_release: - # root.select_next_key("INTERACT") + # Button: - # id: interact_key_input - # text: root.interact_key - # size_hint: 0.1, 0.1 - # disabled: True - # font_name: root.font + # id: enter_code_button + # text: root.validate_label + # pos_hint: {"center_x":0.25, "center_y": 0.225} + # size_hint: 0.3, 0.1 # font_size: 20*root.font_ratio - # pos_hint: {"x":0.65, "y": 0.1} - # color: TEXT_FONT_COLOR diff --git a/screens/settings.py b/screens/settings.py index e434b15..5dc1bad 100644 --- a/screens/settings.py +++ b/screens/settings.py @@ -6,36 +6,107 @@ # Changement de langue (fr en) # Réglage volume musique bruitage # Désactiver les pubs +# Revoir le tutoriel - -from kivy.uix.screenmanager import Screen -from kivy.properties import StringProperty, ObjectProperty, NumericProperty -from kivy.core.window import Window +# from kivy.uix.spinner import Spinner +from kivy.properties import StringProperty, NumericProperty, ListProperty from tools.path import ( - PATH_TITLE_FONT, - PATH_IMAGES + PATH_IMAGES, + PATH_TEXT_FONT +) +from tools.kivy_tools import ( + ImprovedScreen +) +from tools.constants import ( + USER_DATA, + LANGUAGES_LIST, + DICT_LANGUAGE_CORRESPONDANCE, + DICT_LANGUAGE_NAME_TO_CODE, + TEXT, + __version__ ) +from tools import ( + music_mixer, + sound_mixer +) + +class SettingsScreen(ImprovedScreen): + + current_language = StringProperty( + DICT_LANGUAGE_CORRESPONDANCE[USER_DATA.language]) + values_language_list = ListProperty() + + sound_volume_label = StringProperty() + music_volume_label = StringProperty() + apply_label = StringProperty() + language_label = StringProperty() + disable_ads_label = StringProperty() + enter_code_label = StringProperty() + validate_label = StringProperty() + tutorial_label = StringProperty() + version_label = StringProperty() + + sound_volume_value = NumericProperty(0.5) + music_volume_value = NumericProperty(0.5) -class SettingsScreen(Screen): def __init__(self, **kw): - super().__init__(**kw) - - path_images = PATH_IMAGES - font_name = PATH_TITLE_FONT - high_score = StringProperty("") - top_key = StringProperty() - left_key = StringProperty("") - bottom_key = StringProperty("") - right_key = StringProperty("") - interact_key = StringProperty("") - path_back_image = PATH_IMAGES + "settings_background.png" - font_ratio = NumericProperty(0) - width_back_image = ObjectProperty(Window.size[0]) - height_back_image = ObjectProperty(Window.size[0] * 392 / 632) - - def init_screen(self): - self.font_ratio = Window.size[0] / 800 - self.width_back_image = Window.size[0] - self.height_back_image = Window.size[0] * 392 / 632 + super().__init__( + back_image_path=PATH_IMAGES + "settings_background.jpg", + font_name=PATH_TEXT_FONT, + **kw) + + def load_labels(self): + """ + Load the text labels of the screen. + """ + self.sound_volume_label = TEXT.settings["sound_volume"] + self.music_volume_label = TEXT.settings["music_volume"] + self.apply_label = TEXT.settings["apply"] + self.language_label = TEXT.settings["language"] + self.validate_label = TEXT.settings["validate"] + self.tutorial_label = TEXT.settings["tutorial"] + self.version_label = TEXT.settings["version"] + __version__ + + def on_enter(self, *args): + # Load the labels + self.load_labels() + # Set the values of the language spinner + self.values_language_list = LANGUAGES_LIST + return super().on_enter(*args) + + def change_language(self, language_name): + """ + Change the language of the game interface. + + Parameters + ---------- + language_name : str + Name of the language. + """ + language_code = DICT_LANGUAGE_NAME_TO_CODE[language_name] + USER_DATA.language = language_code + TEXT.change_language(language_code) + self.load_labels() + + def go_to_menu(self): + """ + Go back to the main menu. + """ + + self.manager.current = "menu" + + def apply_music_settings(self): + """ + Apply the music settings choosed by the user using the sliders. + """ + + music_mixer.change_volume(self.music_volume_value) + sound_mixer.change_volume(self.sound_volume_value) + + USER_DATA.music_volume = self.music_volume_value + USER_DATA.sound_effects_volume = self.sound_volume_value + + def watch_tutorial(self): + # TODO pass diff --git a/src/BListener.java b/src/BListener.java new file mode 100644 index 0000000..734c2f1 --- /dev/null +++ b/src/BListener.java @@ -0,0 +1,19 @@ +package org.org.kivads; + +import com.google.android.gms.ads.AdListener; +public class BListener extends AdListener { + + private boolean loaded; + private boolean clicked; + + @Override + public void onAdLoaded() { + loaded = true; + } + + @Override + public void onAdOpened(){ + clicked = true; + } + +} diff --git a/src/FullScreen.java b/src/FullScreen.java new file mode 100644 index 0000000..5ac2cf6 --- /dev/null +++ b/src/FullScreen.java @@ -0,0 +1,15 @@ +package org.org.kivads; + +import com.google.android.gms.ads.FullScreenContentCallback; + +public class FullScreen extends FullScreenContentCallback { + + private boolean dismissed; + + @Override + public void onAdDismissedFullScreenContent() { + // Called when the ad is dismissed + dismissed = true; + + } +} diff --git a/src/ICallback.java b/src/ICallback.java new file mode 100644 index 0000000..4281c55 --- /dev/null +++ b/src/ICallback.java @@ -0,0 +1,21 @@ +package org.org.kivads; + +import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback; +import com.google.android.gms.ads.interstitial.InterstitialAd; + + +public class ICallback extends InterstitialAdLoadCallback { + + private InterstitialAd mInterstitialAd; + + private boolean loaded; + + @Override + public void onAdLoaded(InterstitialAd interstitialAd) { + // The mInterstitialAd reference will be null until + // an ad is loaded. + mInterstitialAd = interstitialAd; + loaded = true; + } + +} diff --git a/src/RCallback.java b/src/RCallback.java new file mode 100644 index 0000000..d68e510 --- /dev/null +++ b/src/RCallback.java @@ -0,0 +1,21 @@ +package org.org.kivads; + +import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback; +import com.google.android.gms.ads.rewarded.RewardedAd; + + +public class RCallback extends RewardedAdLoadCallback { + + private RewardedAd mRewardedAd; + + private boolean loaded; + + @Override + public void onAdLoaded(RewardedAd rewardedAd) { + // The mRewardedAd reference will be null until + // an ad is loaded. + mRewardedAd = rewardedAd; + loaded = true; + } + +} diff --git a/src/RICallback.java b/src/RICallback.java new file mode 100644 index 0000000..bd95b3a --- /dev/null +++ b/src/RICallback.java @@ -0,0 +1,21 @@ +package org.org.kivads; + +import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAdLoadCallback; +import com.google.android.gms.ads.rewardedinterstitial.RewardedInterstitialAd; + + +public class RICallback extends RewardedInterstitialAdLoadCallback { + + private RewardedInterstitialAd mRewardedInterstitialAd; + + private boolean loaded; + + @Override + public void onAdLoaded(RewardedInterstitialAd rewardedAd) { + // The mRewardedAd reference will be null until + // an ad is loaded. + mRewardedInterstitialAd = rewardedAd; + loaded = true; + } + +} diff --git a/tools/__init__.py b/tools/__init__.py index d926147..b0e4c2a 100644 --- a/tools/__init__.py +++ b/tools/__init__.py @@ -26,7 +26,10 @@ ) from tools.constants import ( - USER_DATA + USER_DATA, + MUSIC_LIST, + SOUND_LIST, + START_MUSIC_LIST ) from tools.postrias import Game @@ -37,8 +40,9 @@ ############### # Load the dictionnaries -MUSIC_DICT = load_sounds(PATH_MUSICS, USER_DATA.music_volume) -SOUND_DICT = load_sounds(PATH_SOUNDS, USER_DATA.sound_effects_volume) +MUSIC_DICT = load_sounds(START_MUSIC_LIST, PATH_MUSICS, USER_DATA.music_volume) +SOUND_DICT = load_sounds([], PATH_SOUNDS, + USER_DATA.sound_effects_volume) # Create the mixer music_mixer = DynamicMusicMixer(MUSIC_DICT, USER_DATA.music_volume) diff --git a/tools/constants.py b/tools/constants.py index c690de0..e019bd1 100644 --- a/tools/constants.py +++ b/tools/constants.py @@ -111,21 +111,28 @@ def __init__(self) -> None: ### Language ### - DICT_LANGUAGE_CORRESPONDANCE = { "french": "Français", "english": "English" } +DICT_LANGUAGE_NAME_TO_CODE = { + "Français": "french", + "English": "english" +} +LANGUAGES_LIST = tuple(DICT_LANGUAGE_CORRESPONDANCE.values()) class Text(): def __init__(self, language) -> None: + self.language = language self.change_language(language) def change_language(self, language): """ Change the language of the text contained in the class. """ + # Change the language + self.language = language # Load the json file data = load_json_file(PATH_LANGUAGE + language + ".json") @@ -149,4 +156,9 @@ def change_language(self, language): ### Colors ### BACKGROUND_COLOR = (0, 0, 0, 1) TITLE_FONT_COLOR = (0, 0, 0, 1) -TEXT_FONT_COLOR = (50 / 255, 50 / 255, 50 / 255, 1) +TEXT_FONT_COLOR = (0, 0, 0, 1) + +### Musics ### +MUSIC_LIST = ["game_music.mp3", "time_of_the_apocalypse.mp3"] +SOUND_LIST = ["decision.wav", "decree.wav", "guillotine.wav"] +START_MUSIC_LIST = ["cinematic_dramatic.mp3", "my_office.mp3"] diff --git a/tools/game_tools/sound.py b/tools/game_tools/sound.py index 39bd231..0f705a6 100644 --- a/tools/game_tools/sound.py +++ b/tools/game_tools/sound.py @@ -6,8 +6,6 @@ ### Imports ### ############### -import os - from math import exp from kivy.core.audio import SoundLoader @@ -65,6 +63,17 @@ def __init__(self, dict_music, volume): self.dico_frame_state = dico_frame_state self.volume = volume + def add_sounds(self, sound_dict): + for sound_name in sound_dict: + self.dico_frame_state[sound_name] = 0 + self.musics[sound_name] = sound_dict[sound_name] + self.musics[sound_name].volume = self.volume + + def add_sound(self, sound, sound_name): + self.dico_frame_state[sound_name] = 0 + self.musics[sound_name] = sound + self.musics[sound_name].volume = self.volume + def fade_out(self, name, duration, mode="linear"): if mode == "exp": self.instructions.append(("exp_fade_out", name, duration)) @@ -155,7 +164,7 @@ def exp_fade_out(t): return 1 - exp((t - 60) * 0.15) -def load_sounds(foldername: str, volume: float) -> dict: +def load_sounds(music_list: str, foldername: str, volume: float) -> dict: """ Load all sounds of a folder at once. @@ -173,7 +182,7 @@ def load_sounds(foldername: str, volume: float) -> dict: Dictionnary with the loaded sounds. """ sound_dict = {} - for file in os.listdir(foldername): + for file in music_list: name_file = file.split(".")[0] sound_dict[name_file] = SoundLoader.load(foldername + file) sound_dict[name_file].volume = volume diff --git a/tools/kivy_tools/image_with_text.kv b/tools/kivy_tools/image_with_text.kv index 5a4074b..118ddb9 100644 --- a/tools/kivy_tools/image_with_text.kv +++ b/tools/kivy_tools/image_with_text.kv @@ -10,7 +10,7 @@ text_size: (root.width*root.text_filling_ratio,None) color: root.text_color font_name: root.text_font_name - font_size: root.text_font_size * root.parent.font_ratio + font_size: root.text_font_size * root.parent.font_ratio * root.parent.font_size_expand halign: root.text_halign valign: root.text_valign outline_color: root.text_outline_color diff --git a/tools/kivy_tools/image_with_text_button.kv b/tools/kivy_tools/image_with_text_button.kv index c234ecf..52b84f4 100644 --- a/tools/kivy_tools/image_with_text_button.kv +++ b/tools/kivy_tools/image_with_text_button.kv @@ -10,7 +10,7 @@ text_size: (root.width*root.text_filling_ratio,None) color: root.text_color font_name: root.text_font_name - font_size: root.text_font_size * root.parent.font_ratio + font_size: root.text_font_size * root.parent.font_ratio * root.parent.font_size_expand halign: root.text_halign valign: root.text_valign Button: diff --git a/tools/kivy_tools/image_with_text_button.py b/tools/kivy_tools/image_with_text_button.py index 38a611b..69acaa4 100644 --- a/tools/kivy_tools/image_with_text_button.py +++ b/tools/kivy_tools/image_with_text_button.py @@ -11,7 +11,8 @@ from kivy.uix.image import Image from kivy.properties import ( StringProperty, - ObjectProperty + ObjectProperty, + NumericProperty ) ############# @@ -31,5 +32,5 @@ class ImageWithTextButton(Image): text_filling_ratio = 0.9 text_halign = "center" text_valign = "center" - text_font_size = 15 + text_font_size = NumericProperty(15) release_function = ObjectProperty() diff --git a/tools/kivy_tools/images/close_button.png b/tools/kivy_tools/images/close_button.png deleted file mode 100644 index 9177796..0000000 Binary files a/tools/kivy_tools/images/close_button.png and /dev/null differ diff --git a/tools/kivy_tools/images/defaulttheme.png b/tools/kivy_tools/images/defaulttheme.png index 9e8e9ac..416758c 100644 Binary files a/tools/kivy_tools/images/defaulttheme.png and b/tools/kivy_tools/images/defaulttheme.png differ diff --git a/tools/kivy_tools/screen.py b/tools/kivy_tools/screen.py index 81f385e..157cbdb 100644 --- a/tools/kivy_tools/screen.py +++ b/tools/kivy_tools/screen.py @@ -24,6 +24,7 @@ ### Local imports ### from tools.basic_tools import get_image_size +from tools.constants import MOBILE_MODE ############### ### Classes ### @@ -44,6 +45,7 @@ class ImprovedScreen(Screen): # Create the font_name properties font_ratio = NumericProperty(1) font_name = StringProperty("Roboto") + font_size_expand = 1 def __init__(self, font_name="Roboto", back_image_path=None, **kw): @@ -136,6 +138,8 @@ def on_pre_enter(self, *args): if not self.is_loaded: self.preload() + self.update_font_ratio() + def on_enter(self, *args): """ Initialize the screen when it is opened. @@ -173,7 +177,12 @@ def update_font_ratio(self): """ Update the font_name ratio to use on the screen to keep letter size constant with Window size changes. """ - self.font_ratio = Window.size[1] / 600 + if MOBILE_MODE: + self.font_ratio = Window.size[1] / \ + 600 + (Window.size[0] / Window.size[1] - 1) * 0.5 + else: + self.font_ratio = Window.size[1] / \ + 600 + (Window.size[0] / Window.size[1] - 1) * 0.5 def disable_widget(self, widget_id: str): """ diff --git a/tools/kivy_tools/tools_kivy.py b/tools/kivy_tools/tools_kivy.py index b221914..3453bc0 100644 --- a/tools/kivy_tools/tools_kivy.py +++ b/tools/kivy_tools/tools_kivy.py @@ -277,7 +277,8 @@ def on_is_open(self, instance, value): text=value, size_hint_y=None, height=self.height, - font_name=self.font_name + font_name=self.font_name, + font_size=self.font_size ) btn.on_release = partial(self.on_button_press, btn) self._dropdown.add_widget(btn)