diff --git a/games/transmission/Makefile.Android b/games/transmission/Makefile.Android new file mode 100644 index 00000000..2943bb4c --- /dev/null +++ b/games/transmission/Makefile.Android @@ -0,0 +1,289 @@ +#************************************************************************************************** +# +# raylib makefile for Android project (APK building) +# +# Copyright (c) 2017 Ramon Santamaria (@raysan5) +# +# This software is provided "as-is", without any express or implied warranty. In no event +# will the authors be held liable for any damages arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, including commercial +# applications, and to alter it and redistribute it freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not claim that you +# wrote the original software. If you use this software in a product, an acknowledgment +# in the product documentation would be appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not be misrepresented +# as being the original software. +# +# 3. This notice may not be removed or altered from any source distribution. +# +#************************************************************************************************** + +# Define required raylib variables +PLATFORM ?= PLATFORM_ANDROID +RAYLIB_PATH = C:\GitHub\raylib + +# Required path variables +# NOTE: JAVA_HOME must be set to JDK +ANDROID_HOME = C:/android-sdk +ANDROID_NDK = C:/android-ndk +ANDROID_TOOLCHAIN = C:/android_toolchain_arm_api16 +ANDROID_BUILD_TOOLS = $(ANDROID_HOME)/build-tools/26.0.2 +ANDROID_PLATFORM_TOOLS = $(ANDROID_HOME)/platform-tools +JAVA_HOME = C:/PROGRA~1/Java/jdk1.8.0_144 + +# Android project configuration variables +PROJECT_NAME ?= raylib_game +PROJECT_LIBRARY_NAME ?= main +PROJECT_BUILD_PATH ?= android.$(PROJECT_NAME) +PROJECT_RESOURCES_PATH ?= resources +PROJECT_SOURCE_FILES ?= raylib_game.c + +# Some source files are placed in directories, when compiling to some +# output directory other than source, that directory must pre-exist. +# Here we get a list of required folders that need to be created on +# code output folder $(PROJECT_BUILD_PATH)\obj to avoid GCC errors. +PROJECT_SOURCE_DIRS = $(sort $(dir $(PROJECT_SOURCE_FILES))) + +# Android app configuration variables +APP_LABEL_NAME ?= rGame +APP_COMPANY_NAME ?= raylib +APP_PRODUCT_NAME ?= rgame +APP_VERSION_CODE ?= 1 +APP_VERSION_NAME ?= 1.0 +APP_ICON_LDPI ?= $(RAYLIB_PATH)\logo\logo36x36.png +APP_ICON_MDPI ?= $(RAYLIB_PATH)\logo\logo48x48.png +APP_ICON_HDPI ?= $(RAYLIB_PATH)\logo\logo72x72.png +APP_SCREEN_ORIENTATION ?= landscape +APP_KEYSTORE_PASS ?= raylib + +# Library type used for raylib and OpenAL Soft: STATIC (.a) or SHARED (.so/.dll) +RAYLIB_LIBTYPE ?= STATIC +OPENAL_LIBTYPE ?= STATIC +RAYLIB_LIB_PATH = $(RAYLIB_PATH)\release\libs\android\armeabi-v7a +OPENAL_LIB_PATH = $(RAYLIB_PATH)\release\libs\android\armeabi-v7a + +# Shared libs must be added to APK if required +# NOTE: Generated NativeLoader.java automatically load those libraries +ifeq ($(RAYLIB_LIBTYPE),SHARED) + PROJECT_SHARED_LIBS = lib/armeabi-v7a/libraylib.so +endif +ifeq ($(OPENAL_LIBTYPE),SHARED) + PROJECT_SHARED_LIBS += lib/armeabi-v7a/libopenal.so +endif + +# Compiler and archiver +# NOTE: GCC is being deprectated in Android NDK r16 +CC = $(ANDROID_TOOLCHAIN)/bin/arm-linux-androideabi-gcc +AR = $(ANDROID_TOOLCHAIN)/bin/arm-linux-androideabi-ar + +# Compiler flags for arquitecture +CFLAGS = -std=c99 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 +# Compilation functions attributes options +CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC +# Compiler options for the linker +CFLAGS += -Wall -Wa,--noexecstack -Wformat -Werror=format-security -no-canonical-prefixes +# Preprocessor macro definitions +CFLAGS += -DANDROID -DPLATFORM_ANDROID -D__ANDROID_API__=16 + +# Paths containing required header files +INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/release/include -I$(RAYLIB_PATH)/src/external/android/native_app_glue + +# Linker options +LDFLAGS = -Wl,-soname,lib$(PROJECT_LIBRARY_NAME).so -Wl,--exclude-libs,libatomic.a +LDFLAGS += -Wl,--build-id -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings +# Force linking of library module to define symbol +LDFLAGS += -u ANativeActivity_onCreate +# Library paths containing required libs +LDFLAGS += -L. -L$(PROJECT_BUILD_PATH)/obj -L$(PROJECT_BUILD_PATH)/lib/armeabi-v7a + +# Define any libraries to link into executable +# if you want to link libraries (libname.so or libname.a), use the -lname +LDLIBS = -lraylib -lnative_app_glue -llog -landroid -lEGL -lGLESv2 -lOpenSLES -latomic -lc -lm -ldl + +# Generate target objects list from PROJECT_SOURCE_FILES +OBJS = $(patsubst %.c, $(PROJECT_BUILD_PATH)/obj/%.o, $(PROJECT_SOURCE_FILES)) + +# Android APK building process... some steps required... +# NOTE: typing 'make' will invoke the default target entry called 'all', +all: create_temp_project_dirs \ + copy_project_required_libs \ + copy_project_resources \ + generate_loader_script \ + generate_android_manifest \ + generate_apk_keystore \ + config_project_package \ + compile_native_app_glue \ + compile_project_code \ + compile_project_class \ + compile_project_class_dex \ + create_project_apk_package \ + sign_project_apk_package \ + zipalign_project_apk_package + +# Create required temp directories for APK building +create_temp_project_dirs: + if not exist $(PROJECT_BUILD_PATH) mkdir $(PROJECT_BUILD_PATH) + if not exist $(PROJECT_BUILD_PATH)\obj mkdir $(PROJECT_BUILD_PATH)\obj + if not exist $(PROJECT_BUILD_PATH)\src mkdir $(PROJECT_BUILD_PATH)\src + if not exist $(PROJECT_BUILD_PATH)\src\com mkdir $(PROJECT_BUILD_PATH)\src\com + if not exist $(PROJECT_BUILD_PATH)\src\com\$(APP_COMPANY_NAME) mkdir $(PROJECT_BUILD_PATH)\src\com\$(APP_COMPANY_NAME) + if not exist $(PROJECT_BUILD_PATH)\src\com\$(APP_COMPANY_NAME)\$(APP_PRODUCT_NAME) mkdir $(PROJECT_BUILD_PATH)\src\com\$(APP_COMPANY_NAME)\$(APP_PRODUCT_NAME) + if not exist $(PROJECT_BUILD_PATH)\lib mkdir $(PROJECT_BUILD_PATH)\lib + if not exist $(PROJECT_BUILD_PATH)\lib\armeabi-v7a mkdir $(PROJECT_BUILD_PATH)\lib\armeabi-v7a + if not exist $(PROJECT_BUILD_PATH)\bin mkdir $(PROJECT_BUILD_PATH)\bin + if not exist $(PROJECT_BUILD_PATH)\res mkdir $(PROJECT_BUILD_PATH)\res + if not exist $(PROJECT_BUILD_PATH)\res\drawable-ldpi mkdir $(PROJECT_BUILD_PATH)\res\drawable-ldpi + if not exist $(PROJECT_BUILD_PATH)\res\drawable-mdpi mkdir $(PROJECT_BUILD_PATH)\res\drawable-mdpi + if not exist $(PROJECT_BUILD_PATH)\res\drawable-hdpi mkdir $(PROJECT_BUILD_PATH)\res\drawable-hdpi + if not exist $(PROJECT_BUILD_PATH)\res\values mkdir $(PROJECT_BUILD_PATH)\res\values + if not exist $(PROJECT_BUILD_PATH)\assets mkdir $(PROJECT_BUILD_PATH)\assets + if not exist $(PROJECT_BUILD_PATH)\assets\$(PROJECT_RESOURCES_PATH) mkdir $(PROJECT_BUILD_PATH)\assets\$(PROJECT_RESOURCES_PATH) + if not exist $(PROJECT_BUILD_PATH)\obj\screens mkdir $(PROJECT_BUILD_PATH)\obj\screens + $(foreach dir, $(PROJECT_SOURCE_DIRS), $(call create_dir, $(dir))) + +define create_dir + if not exist $(PROJECT_BUILD_PATH)\obj\$(1) mkdir $(PROJECT_BUILD_PATH)\obj\$(1) +endef + +# Copy required shared libs for integration into APK +# NOTE: If using shared libs they are loaded by generated NativeLoader.java +copy_project_required_libs: +ifeq ($(RAYLIB_LIBTYPE),SHARED) + copy /Y $(RAYLIB_LIB_PATH)\libraylib.so $(PROJECT_BUILD_PATH)\lib\armeabi-v7a\libraylib.so +endif +ifeq ($(OPENAL_LIBTYPE),SHARED) + copy /Y $(OPENAL_LIB_PATH)\libopenal.so $(PROJECT_BUILD_PATH)\lib\armeabi-v7a\libopenal.so +endif +ifeq ($(RAYLIB_LIBTYPE),STATIC) + copy /Y $(RAYLIB_LIB_PATH)\libraylib.a $(PROJECT_BUILD_PATH)\lib\armeabi-v7a\libraylib.a +endif +ifeq ($(OPENAL_LIBTYPE),STATIC) + copy /Y $(OPENAL_LIB_PATH)\libopenal.a $(PROJECT_BUILD_PATH)\lib\armeabi-v7a\libopenal.a +endif + +# Copy project required resources: strings.xml, icon.png, assets +# NOTE: Required strings.xml is generated and game resources are copied to assets folder +# TODO: Review xcopy usage, it can not be found in some systems! +copy_project_resources: + copy $(APP_ICON_LDPI) $(PROJECT_BUILD_PATH)\res\drawable-ldpi\icon.png /Y + copy $(APP_ICON_MDPI) $(PROJECT_BUILD_PATH)\res\drawable-mdpi\icon.png /Y + copy $(APP_ICON_HDPI) $(PROJECT_BUILD_PATH)\res\drawable-hdpi\icon.png /Y + @echo ^ > $(PROJECT_BUILD_PATH)/res/values/strings.xml + @echo ^^$(APP_LABEL_NAME)^^ >> $(PROJECT_BUILD_PATH)/res/values/strings.xml + if exist $(PROJECT_RESOURCES_PATH) C:\Windows\System32\xcopy $(PROJECT_RESOURCES_PATH) $(PROJECT_BUILD_PATH)\assets\$(PROJECT_RESOURCES_PATH) /Y /E /F + +# Generate NativeLoader.java to load required shared libraries +# NOTE: Probably not the bet way to generate this file... but it works. +generate_loader_script: + @echo package com.$(APP_COMPANY_NAME).$(APP_PRODUCT_NAME); > $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java + @echo. >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java + @echo public class NativeLoader extends android.app.NativeActivity { >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java + @echo static { >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java +ifeq ($(OPENAL_LIBTYPE),SHARED) + @echo System.loadLibrary("openal"); >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java +endif +ifeq ($(RAYLIB_LIBTYPE),SHARED) + @echo System.loadLibrary("raylib"); >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java +endif + @echo System.loadLibrary("$(PROJECT_LIBRARY_NAME)"); >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java + @echo } >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java + @echo } >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java + +# Generate AndroidManifest.xml with all the required options +# NOTE: Probably not the bet way to generate this file... but it works. +generate_android_manifest: + @echo ^ > $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo ^> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo package="com.$(APP_COMPANY_NAME).$(APP_PRODUCT_NAME)" >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo android:versionCode="$(APP_VERSION_CODE)" android:versionName="$(APP_VERSION_NAME)" ^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo ^> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo android:configChanges="orientation|keyboardHidden|screenSize" >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo android:screenOrientation="$(APP_SCREEN_ORIENTATION)" android:launchMode="singleTask" >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo android:clearTaskOnLaunch="true"^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml + +# Generate storekey for APK signing: $(PROJECT_NAME).keystore +# NOTE: Configure here your Distinguished Names (-dname) if required! +generate_apk_keystore: + if not exist $(PROJECT_BUILD_PATH)/$(PROJECT_NAME).keystore $(JAVA_HOME)/bin/keytool -genkeypair -validity 1000 -dname "CN=$(APP_COMPANY_NAME),O=Android,C=ES" -keystore $(PROJECT_BUILD_PATH)/$(PROJECT_NAME).keystore -storepass $(APP_KEYSTORE_PASS) -keypass $(APP_KEYSTORE_PASS) -alias $(PROJECT_NAME)Key -keyalg RSA + +# Config project package and resource using AndroidManifest.xml and res/values/strings.xml +# NOTE: Generates resources file: src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/R.java +config_project_package: + $(ANDROID_BUILD_TOOLS)/aapt package -f -m -S $(PROJECT_BUILD_PATH)/res -J $(PROJECT_BUILD_PATH)/src -M $(PROJECT_BUILD_PATH)/AndroidManifest.xml -I $(ANDROID_HOME)/platforms/android-16/android.jar + +# Compile native_app_glue code as static library: obj/libnative_app_glue.a +compile_native_app_glue: + $(CC) -c $(RAYLIB_PATH)/src/external/android/native_app_glue/android_native_app_glue.c -o $(PROJECT_BUILD_PATH)/obj/native_app_glue.o $(CFLAGS) + $(AR) rcs $(PROJECT_BUILD_PATH)/obj/libnative_app_glue.a $(PROJECT_BUILD_PATH)/obj/native_app_glue.o + +# Compile project code into a shared library: lib/lib$(PROJECT_LIBRARY_NAME).so +compile_project_code: $(OBJS) + $(CC) -o $(PROJECT_BUILD_PATH)/lib/armeabi-v7a/lib$(PROJECT_LIBRARY_NAME).so $(OBJS) -shared $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) + +# Compile all .c files required into object (.o) files +# NOTE: Those files will be linked into a shared library +$(PROJECT_BUILD_PATH)/obj/%.o:%.c + $(CC) -c $^ -o $@ $(INCLUDE_PATHS) $(CFLAGS) --sysroot=$(ANDROID_TOOLCHAIN)/sysroot + +# Compile project .java code into .class (Java bytecode) +compile_project_class: + $(JAVA_HOME)/bin/javac -verbose -source 1.7 -target 1.7 -d $(PROJECT_BUILD_PATH)/obj -bootclasspath $(JAVA_HOME)/jre/lib/rt.jar -classpath $(ANDROID_HOME)/platforms/android-16/android.jar;$(PROJECT_BUILD_PATH)/obj -sourcepath $(PROJECT_BUILD_PATH)/src $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/R.java $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java + +# Compile .class files into Dalvik executable bytecode (.dex) +# NOTE: Since Android 5.0, Dalvik interpreter (JIT) has been replaced by ART (AOT) +compile_project_class_dex: + $(ANDROID_BUILD_TOOLS)/dx --verbose --dex --output=$(PROJECT_BUILD_PATH)/bin/classes.dex $(PROJECT_BUILD_PATH)/obj + +# Create Android APK package: bin/$(PROJECT_NAME).unsigned.apk +# NOTE: Requires compiled classes.dex and lib$(PROJECT_LIBRARY_NAME).so +# NOTE: Use -A resources to define additional directory in which to find raw asset files +create_project_apk_package: + $(ANDROID_BUILD_TOOLS)/aapt package -f -M $(PROJECT_BUILD_PATH)/AndroidManifest.xml -S $(PROJECT_BUILD_PATH)/res -A $(PROJECT_BUILD_PATH)/assets -I $(ANDROID_HOME)/platforms/android-16/android.jar -F $(PROJECT_BUILD_PATH)/bin/$(PROJECT_NAME).unsigned.apk $(PROJECT_BUILD_PATH)/bin + cd $(PROJECT_BUILD_PATH) && $(ANDROID_BUILD_TOOLS)/aapt add bin/$(PROJECT_NAME).unsigned.apk lib/armeabi-v7a/lib$(PROJECT_LIBRARY_NAME).so $(PROJECT_SHARED_LIBS) + +# Create signed APK package using generated Key: bin/$(PROJECT_NAME).signed.apk +sign_project_apk_package: + $(JAVA_HOME)/bin/jarsigner -keystore $(PROJECT_BUILD_PATH)/$(PROJECT_NAME).keystore -storepass $(APP_KEYSTORE_PASS) -keypass $(APP_KEYSTORE_PASS) -signedjar $(PROJECT_BUILD_PATH)/bin/$(PROJECT_NAME).signed.apk $(PROJECT_BUILD_PATH)/bin/$(PROJECT_NAME).unsigned.apk $(PROJECT_NAME)Key + +# Create zip-aligned APK package: $(PROJECT_NAME).apk +zipalign_project_apk_package: + $(ANDROID_BUILD_TOOLS)/zipalign -f 4 $(PROJECT_BUILD_PATH)/bin/$(PROJECT_NAME).signed.apk $(PROJECT_NAME).apk + +# Install $(PROJECT_NAME).apk to default emulator/device +# NOTE: Use -e (emulator) or -d (device) parameters if required +install: + $(ANDROID_PLATFORM_TOOLS)/adb install -r $(PROJECT_NAME).apk + +# Monitorize output log coming from device, only raylib tag +logcat: + $(ANDROID_PLATFORM_TOOLS)/adb logcat -c + $(ANDROID_PLATFORM_TOOLS)/adb logcat raylib:V *:S + +# Install and monitorize $(PROJECT_NAME).apk to default emulator/device +deploy: + $(ANDROID_PLATFORM_TOOLS)/adb install -r $(PROJECT_NAME).apk + $(ANDROID_PLATFORM_TOOLS)/adb logcat -c + $(ANDROID_PLATFORM_TOOLS)/adb logcat raylib:V *:S + +#$(ANDROID_PLATFORM_TOOLS)/adb logcat *:W + +# Clean everything +clean: + del $(PROJECT_BUILD_PATH)\* /f /s /q + rmdir $(PROJECT_BUILD_PATH) /s /q + @echo Cleaning done diff --git a/games/transmission/resources/audio/fx_batman.ogg b/games/transmission/resources/audio/fx_batman.ogg new file mode 100644 index 00000000..d3e25ae2 Binary files /dev/null and b/games/transmission/resources/audio/fx_batman.ogg differ diff --git a/games/transmission/resources/audio/fx_button.ogg b/games/transmission/resources/audio/fx_button.ogg new file mode 100644 index 00000000..8d0747ca Binary files /dev/null and b/games/transmission/resources/audio/fx_button.ogg differ diff --git a/games/transmission/resources/audio/fx_grab.ogg b/games/transmission/resources/audio/fx_grab.ogg new file mode 100644 index 00000000..b78e1315 Binary files /dev/null and b/games/transmission/resources/audio/fx_grab.ogg differ diff --git a/games/transmission/resources/audio/fx_leave.ogg b/games/transmission/resources/audio/fx_leave.ogg new file mode 100644 index 00000000..24abdbee Binary files /dev/null and b/games/transmission/resources/audio/fx_leave.ogg differ diff --git a/games/transmission/resources/audio/fx_message.ogg b/games/transmission/resources/audio/fx_message.ogg new file mode 100644 index 00000000..60de6655 Binary files /dev/null and b/games/transmission/resources/audio/fx_message.ogg differ diff --git a/games/transmission/resources/audio/fx_newspaper.ogg b/games/transmission/resources/audio/fx_newspaper.ogg new file mode 100644 index 00000000..bcc54841 Binary files /dev/null and b/games/transmission/resources/audio/fx_newspaper.ogg differ diff --git a/games/transmission/resources/audio/fx_place.ogg b/games/transmission/resources/audio/fx_place.ogg new file mode 100644 index 00000000..a300a968 Binary files /dev/null and b/games/transmission/resources/audio/fx_place.ogg differ diff --git a/games/transmission/resources/audio/fx_typing.ogg b/games/transmission/resources/audio/fx_typing.ogg new file mode 100644 index 00000000..89a09daf Binary files /dev/null and b/games/transmission/resources/audio/fx_typing.ogg differ diff --git a/games/transmission/resources/audio/music_mission.ogg b/games/transmission/resources/audio/music_mission.ogg new file mode 100644 index 00000000..2de719bb Binary files /dev/null and b/games/transmission/resources/audio/music_mission.ogg differ diff --git a/games/transmission/resources/audio/music_title.ogg b/games/transmission/resources/audio/music_title.ogg new file mode 100644 index 00000000..d75b1ddc Binary files /dev/null and b/games/transmission/resources/audio/music_title.ogg differ diff --git a/games/transmission/resources/audio/s_p_y.xm b/games/transmission/resources/audio/s_p_y.xm new file mode 100644 index 00000000..ebbdbf93 Binary files /dev/null and b/games/transmission/resources/audio/s_p_y.xm differ diff --git a/games/transmission/resources/audio/spy_versus_spy.xm b/games/transmission/resources/audio/spy_versus_spy.xm new file mode 100644 index 00000000..11602adc Binary files /dev/null and b/games/transmission/resources/audio/spy_versus_spy.xm differ diff --git a/games/transmission/resources/fonts/Lora-Bold.ttf b/games/transmission/resources/fonts/Lora-Bold.ttf new file mode 100644 index 00000000..e48c4262 Binary files /dev/null and b/games/transmission/resources/fonts/Lora-Bold.ttf differ diff --git a/games/transmission/resources/fonts/Lora-BoldItalic.ttf b/games/transmission/resources/fonts/Lora-BoldItalic.ttf new file mode 100644 index 00000000..19b03226 Binary files /dev/null and b/games/transmission/resources/fonts/Lora-BoldItalic.ttf differ diff --git a/games/transmission/resources/fonts/fontTitle.ttf b/games/transmission/resources/fonts/fontTitle.ttf new file mode 100644 index 00000000..13f5dc7d Binary files /dev/null and b/games/transmission/resources/fonts/fontTitle.ttf differ diff --git a/games/transmission/resources/fonts/traveling_typewriter.ttf b/games/transmission/resources/fonts/traveling_typewriter.ttf new file mode 100644 index 00000000..5d9d7c9b Binary files /dev/null and b/games/transmission/resources/fonts/traveling_typewriter.ttf differ diff --git a/games/transmission/resources/missions.txt b/games/transmission/resources/missions.txt new file mode 100644 index 00000000..346e54e4 --- /dev/null +++ b/games/transmission/resources/missions.txt @@ -0,0 +1,65 @@ +# Total missions +# NOTE: Missions follow the order of this file +t 4 +# ----------------------------------------------------------------- +# Briefing of the mission +b Se ha visto al Presidente en actitud cariñosa con una persona que no es la Primera Dama. Una situación comprometida que definirá el curso de la historia... Especialmente en campaña electoral y siendo del partido conservador... ¡El pueblo debe saber! +# +# Mission keyword +k oviparo +# +# Message to be coded +# NOTE: Sensible words must be noted using @ +m El @presidente es visto en un @hotel acompañado de su @amante . +# +# Solution to mission +# NOTE: Provide the correct solution nums, according to above words +# WARNING: Always provide 8 values, use -1 for not used ones +# Coding Words: POLLO = 0, CONEJO, HUEVO, NIDO, AIRE, ARMARIO, AGUJERO, PLATANO, PASTEL, MERCADO, RATON, MELON +s 0 3 2 -1 -1 -1 -1 -1 +# ----------------------------------------------------------------- +# Briefing of the mission +b Se ha visto un ovni sobrevolando la ciudad, al parecer se prevee un ataque alienígena inminente que definirá el curso de la historia... ¡El pueblo debe saber! +# +# Mission keyword +k roedor +# +# Message to be coded +# NOTE: Sensible words must be noted using @ +m Un @ovni ha sido detectado en el @cielo del @pais . Preparaos para el ataque de un @alien . +# +# NOTE: Provide the correct solution nums, according to above words +# WARNING: Always provide 8 values, use -1 for not used ones +# Coding Words: POLLO = 0, CONEJO, HUEVO, NIDO, AIRE, ARMARIO, AGUJERO, PLATANO, PASTEL, MERCADO, RATON, MELON +s 1 6 5 10 -1 -1 -1 -1 +# ----------------------------------------------------------------- +# Briefing of the mission +b Se ha filtrado una inminente subida del precio de un producto básico para todo el mundo: el ajo. Le evolución de su precio de mercado definirá el curso de la historia... ¡El pueblo debe saber! +# +# Mission keyword +k comida +# +# Message to be coded +# NOTE: Sensible words must be noted using @ +m Sube el @precio del @ajo. ¡Un @desastre inminente! +# +# NOTE: Provide the correct solution nums, according to above words +# WARNING: Always provide 8 values, use -1 for not used ones +# Coding Words: POLLO = 0, CONEJO, HUEVO, NIDO, AIRE, ARMARIO, AGUJERO, PLATANO, PASTEL, MERCADO, RATON, MELON +s 9 7 2 -1 -1 -1 -1 -1 +# ----------------------------------------------------------------- +# Briefing of the mission +b Se ha visto a un famoso presentador de TV deshaciéndose del cuerpo de un rival de otra cadena. Una pérdida que definirá el curso de la historia... Especialmente cuando su programa podría no continuar... ¡El pueblo debe saber! +# +# Mission keyword +k postre +# +# Message to be coded +# NOTE: Sensible words must be noted using @ +m Un @presentador se deshace del @cuerpo de su rival. ¡Peligra el @programa del Prime Time! +# +# NOTE: Provide the correct solution nums, according to above words +# WARNING: Always provide 8 values, use -1 for not used ones +# Coding Words: POLLO = 0, CONEJO, HUEVO, NIDO, AIRE, ARMARIO, AGUJERO, PLATANO, PASTEL, MERCADO, RATON, MELON +s 7 11 8 -1 -1 -1 -1 -1 +# ----------------------------------------------------------------- \ No newline at end of file diff --git a/games/transmission/resources/textures/cw_logo.png b/games/transmission/resources/textures/cw_logo.png new file mode 100644 index 00000000..bc4011d8 Binary files /dev/null and b/games/transmission/resources/textures/cw_logo.png differ diff --git a/games/transmission/resources/textures/ending_background.png b/games/transmission/resources/textures/ending_background.png new file mode 100644 index 00000000..6577be63 Binary files /dev/null and b/games/transmission/resources/textures/ending_background.png differ diff --git a/games/transmission/resources/textures/ending_newspaper.png b/games/transmission/resources/textures/ending_newspaper.png new file mode 100644 index 00000000..f44e646d Binary files /dev/null and b/games/transmission/resources/textures/ending_newspaper.png differ diff --git a/games/transmission/resources/textures/message_background.png b/games/transmission/resources/textures/message_background.png new file mode 100644 index 00000000..78c00a59 Binary files /dev/null and b/games/transmission/resources/textures/message_background.png differ diff --git a/games/transmission/resources/textures/message_vignette.png b/games/transmission/resources/textures/message_vignette.png new file mode 100644 index 00000000..72234c59 Binary files /dev/null and b/games/transmission/resources/textures/message_vignette.png differ diff --git a/games/transmission/resources/textures/mission_background.png b/games/transmission/resources/textures/mission_background.png new file mode 100644 index 00000000..4efe5815 Binary files /dev/null and b/games/transmission/resources/textures/mission_background.png differ diff --git a/games/transmission/resources/textures/mission_backline.png b/games/transmission/resources/textures/mission_backline.png new file mode 100644 index 00000000..2a89d80a Binary files /dev/null and b/games/transmission/resources/textures/mission_backline.png differ diff --git a/games/transmission/resources/textures/mission_words.png b/games/transmission/resources/textures/mission_words.png new file mode 100644 index 00000000..4e4e9d93 Binary files /dev/null and b/games/transmission/resources/textures/mission_words.png differ diff --git a/games/transmission/resources/textures/title_background.png b/games/transmission/resources/textures/title_background.png new file mode 100644 index 00000000..c90d880d Binary files /dev/null and b/games/transmission/resources/textures/title_background.png differ diff --git a/games/transmission/resources/textures/title_ribbon.png b/games/transmission/resources/textures/title_ribbon.png new file mode 100644 index 00000000..1526eba1 Binary files /dev/null and b/games/transmission/resources/textures/title_ribbon.png differ diff --git a/games/transmission/resources/textures/words_base.png b/games/transmission/resources/textures/words_base.png new file mode 100644 index 00000000..a2139030 Binary files /dev/null and b/games/transmission/resources/textures/words_base.png differ diff --git a/games/transmission/screens/screen_ending.c b/games/transmission/screens/screen_ending.c new file mode 100644 index 00000000..e1fd6156 --- /dev/null +++ b/games/transmission/screens/screen_ending.c @@ -0,0 +1,212 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Ending Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" + +#include +#include + +#define MAX_TITLE_CHAR 128 +#define MAX_SUBTITLE_CHAR 256 + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- +static char *codingWords[MAX_CODING_WORDS] = { + "pollo\0", + "conejo\0", + "huevo\0", + "nido\0", + "aire\0", + "armario\0", + "agujero\0", + "platano\0", + "pastel\0", + "mercado\0", + "raton\0", + "melon\0", +}; + +// Ending screen global variables +static int framesCounter; +static int finishScreen; + +static Texture2D texBackground; +static Texture2D texNewspaper; +static Texture2D texVignette; + +static Sound fxNews; + +static float rotation = 0.1f; +static float scale = 0.05f; +static int state = 0; + +static Mission *missions = NULL; + +static bool showResults = false; + +//---------------------------------------------------------------------------------- +// Ending Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Ending Screen Initialization logic +void InitEndingScreen(void) +{ + framesCounter = 0; + finishScreen = 0; + + rotation = 0.1f; + scale = 0.05f; + state = 0; + + texBackground = LoadTexture("resources/textures/ending_background.png"); + texVignette = LoadTexture("resources/textures/message_vignette.png"); + + fxNews = LoadSound("resources/audio/fx_batman.ogg"); + + // TODO: Check game results! + missions = LoadMissions("resources/missions.txt"); + int wordsCount = missions[currentMission].wordsCount; + TraceLog(LOG_WARNING, "Words count %i", wordsCount); + + char title[MAX_TITLE_CHAR] = "\0"; + //char subtitle[MAX_SUBTITLE_CHAR] = "\0"; + + char *ptrTitle = title; + int len = 0; + + for (int i = 0; i < wordsCount; i++) + { + if (messageWords[i].id == missions[currentMission].sols[i]) + { + len = strlen(messageWords[i].text); + strncpy(ptrTitle, messageWords[i].text, len); + ptrTitle += len; + + // title[len] = ' '; + // len++; + // ptrTitle++; + } + else + { + TraceLog(LOG_WARNING, "Coding word: %s", codingWords[messageWords[i].id]); + len = strlen(codingWords[messageWords[i].id]); + TraceLog(LOG_WARNING, "Lenght: %i", len); + strncpy(ptrTitle, codingWords[messageWords[i].id], len); + ptrTitle += len; + + // title[len] = ' '; + // len++; + // ptrTitle++; + } + } + + ptrTitle = '\0'; + + //TraceLog(LOG_WARNING, "Titular: %s", title); + + // Generate newspaper with title and subtitle + Image imNewspaper = LoadImage("resources/textures/ending_newspaper.png"); + SpriteFont fontNews = LoadSpriteFontEx("resources/fonts/Lora-Bold.ttf", 82, 250, 0); + ImageDrawTextEx(&imNewspaper, (Vector2){ 50, 220 }, fontNews, "FRACASO EN LA GGJ18!", fontNews.baseSize, 0, DARKGRAY); + + // TODO: Draw subtitle message + //ImageDrawTextEx(&imNewspaper, (Vector2){ 50, 210 }, fontNews, "SUBE LA ESCALERA!", fontNews.baseSize, 0, DARKGRAY); + + texNewspaper = LoadTextureFromImage(imNewspaper); + UnloadSpriteFont(fontNews); + UnloadImage(imNewspaper); +} + +// Ending Screen Update logic +void UpdateEndingScreen(void) +{ + framesCounter++; + + if (framesCounter == 10) PlaySound(fxNews); + + if (state == 0) + { + rotation += 18.0f; + scale += 0.0096f; + + if (scale >= 1.0f) + { + scale = 1.0f; + state = 1; + } + } + + if ((state == 1) && (IsKeyPressed(KEY_ENTER) || IsButtonPressed())) + { + currentMission++; + + if (currentMission >= totalMissions) finishScreen = 2; + else finishScreen = 1; + } + + if (IsKeyPressed(KEY_SPACE)) showResults = !showResults; +} + +// Ending Screen Draw logic +void DrawEndingScreen(void) +{ + DrawTexture(texBackground, 0, 0, WHITE); + + DrawTexturePro(texNewspaper, (Rectangle){ 0, 0, texNewspaper.width, texNewspaper.height }, + (Rectangle){ GetScreenWidth()/2, GetScreenHeight()/2, texNewspaper.width*scale, texNewspaper.height*scale }, + (Vector2){ (float)texNewspaper.width*scale/2, (float)texNewspaper.height*scale/2 }, rotation, WHITE); + + DrawTextureEx(texVignette, (Vector2){ 0, 0 }, 0.0f, 2.0f, WHITE); + + if (showResults) + { + for (int i = 0; i < missions[currentMission].wordsCount; i++) + { + if (messageWords[i].id == missions[currentMission].sols[i]) DrawText(messageWords[i].text, 10, 10 + 30*i, 20, GREEN); + else DrawText(codingWords[messageWords[i].id], 10, 10 + 30*i, 20, RED); + } + } + + if (state == 1) DrawButton("continuar"); +} + +// Ending Screen Unload logic +void UnloadEndingScreen(void) +{ + UnloadTexture(texBackground); + UnloadTexture(texNewspaper); + UnloadTexture(texVignette); + + UnloadSound(fxNews); + free(missions); +} + +// Ending Screen should finish? +int FinishEndingScreen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/transmission/screens/screen_gameplay.c b/games/transmission/screens/screen_gameplay.c new file mode 100644 index 00000000..00c451fc --- /dev/null +++ b/games/transmission/screens/screen_gameplay.c @@ -0,0 +1,423 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" + +#include +#include +#include + +//#define MAX_CODING_WORDS 12 +//#define MAX_MISSION_WORDS 8 +#define MAX_LINE_CHAR 30 + +/* +// NOTE: Coding words are generic and the same words +// are used for all missions, +typedef enum CodingWords { + POLLO = 0, + CONEJO, + HUEVO, + NIDO, + AIRE, + ARMARIO, + AGUJERO, + COSA, + WORD, +} CodingWords; +*/ + +static char *codingWords[MAX_CODING_WORDS] = { + "pollo\0", + "conejo\0", + "huevo\0", + "nido\0", + "aire\0", + "armario\0", + "agujero\0", + "platano\0", + "pastel\0", + "mercado\0", + "raton\0", + "melon\0" +}; + +// Words to be coded or coding words +/*typedef struct Word { + int id; + Rectangle rec; + Rectangle iniRec; + bool hover; + bool picked; + char text[32]; // text +} Word;*/ + +/* +// Mission information +typedef struct Mission { + int id; + char brief[512]; // Mission briefing + char key[32]; // Mission keyword + char msg[256]; // Message to be coded + int wordsCount; // Number of words to coded + int sols[8]; // Solution code, depends on wordsCount +} Mission; +*/ +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Gameplay screen global variables +static int framesCounter; +static int finishScreen; + +static Texture2D texBackground; +static SpriteFont fontMessage; +static Texture2D texWordsAtlas; +static Texture2D texVignette; + +static Sound fxGrab; +static Sound fxPlace; +static Sound fxLeave; + +static Music musSpy; + +static Word words[MAX_CODING_WORDS] = { 0 }; + +// Hay que hacerlo global, para poder consultar el resultado desde la endingscreen +//static Word messageWords[MAX_MISSION_WORDS] = { 0 }; + +static Mission *missions = NULL; + +static bool canSend = false; + +Vector2 msgOffset = { 430, 300 }; + +//---------------------------------------------------------------------------------- +// Gameplay Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Gameplay Screen Initialization logic +void InitGameplayScreen(void) +{ + framesCounter = 0; + finishScreen = 0; + + fontMessage = LoadSpriteFontEx("resources/fonts/traveling_typewriter.ttf", 30, 250, 0); + + texBackground = LoadTexture("resources/textures/message_background.png"); + texVignette = LoadTexture("resources/textures/message_vignette.png"); + + fxGrab = LoadSound("resources/audio/fx_grab.ogg"); + fxPlace = LoadSound("resources/audio/fx_place.ogg"); + fxLeave = LoadSound("resources/audio/fx_leave.ogg"); + + musSpy = LoadMusicStream("resources/audio/s_p_y.xm"); + PlayMusicStream(musSpy); + +#if defined(PLATFORM_WEB) + #define WORD_ATLAS_FROM_FILE +#endif +#if defined(WORD_ATLAS_FROM_FILE) + texWordsAtlas = LoadTexture("resources/textures/mission_words.png"); +#else + // Generate coding words atlas directly from text + Image imWordsBase = LoadImage("resources/textures/words_base.png"); + Image imWords = GenImageColor(imWordsBase.width, imWordsBase.height*MAX_CODING_WORDS, WHITE); + + for (int i = 0; i < MAX_CODING_WORDS; i++) + { + ImageDraw(&imWords, imWordsBase, + (Rectangle){ 0, 0, imWordsBase.width, imWordsBase.height }, + (Rectangle){ 0, imWordsBase.height*i, imWordsBase.width, imWordsBase.height }); + + ImageDrawTextEx(&imWords,(Vector2){ imWordsBase.width/2 - MeasureTextEx(fontMessage, codingWords[i], + fontMessage.baseSize, 0).x/2, imWordsBase.height*i }, fontMessage, codingWords[i], + fontMessage.baseSize, 0, BLACK); + } + + texWordsAtlas = LoadTextureFromImage(imWords); + + UnloadImage(imWordsBase); + UnloadImage(imWords); +#endif + + // Initialize missions + // WARNING: Some problem with imWords image generation (memory leak?) could cause + // that loading missions before/after generation breaks game, on web is the other way round... :( + missions = LoadMissions("resources/missions.txt"); + TraceLog(LOG_WARNING, "Words count %i", missions[currentMission].wordsCount); + + // Initialize coding words + for (int i = 0; i < MAX_CODING_WORDS; i++) + { + words[i].id = -1; // Not placed anywhere + + words[i].rec.x = 110 + 940*(i/(MAX_CODING_WORDS/2)); + words[i].rec.y = 200 + 60*(i%(MAX_CODING_WORDS/2)); + words[i].rec.width = 140; // texWordsAtlas.width/MAX_MISSIONS + words[i].rec.height = 35; // texWordsAtlas.height/MAX_MISSION_WORDS + words[i].iniRec = words[i].rec; + words[i].hover = false; // Mouse hover detected + words[i].picked = false; // Mouse picked + + //words[i].text = ''; //codingWords[i]; // Fill text if required... + } + + // Analize missions[currentMission].msg string for words! + int msgLen = strlen(missions[currentMission].msg); + + // Add '/' each MAX_LINE_CHAR chars + int currentLine = 1; + int i = currentLine * MAX_LINE_CHAR; + + while (i < msgLen - 1) + { + if (missions[currentMission].msg[i] == ' ') + { + missions[currentMission].msg[i] = '/'; + currentLine++; + i = currentLine*MAX_LINE_CHAR; + } + else i++; + } + + int currentWord = 0; + int offsetX = 0; + int offsetY = 0; + bool foundWord = false; + int wordInitPosX = 0; + int wordInitPosY = 0; + + // TODO: messageWords should be reseted every mission + //memcpy(messageWords, 0, sizeof(Word)*MAX_MISSION_WORDS); + + for (int i = 0; i < msgLen; i++) + { + char c = missions[currentMission].msg[i]; + if (foundWord && (c == ' ' || c == '.')) + { + foundWord = false; + + messageWords[currentWord - 1].rec.width = (int)MeasureTextEx(fontMessage, SubText(missions[currentMission].msg, wordInitPosX, (i - wordInitPosX)), 30, 0).x; + messageWords[currentWord - 1].rec.height = fontMessage.baseSize; + + //TODO: Guardar en message + strncpy(messageWords[currentWord - 1].text, SubText(missions[currentMission].msg, wordInitPosX, (i - wordInitPosX)), i - wordInitPosX); + } + + if (c == '@') // One word to change + { + foundWord = true; + missions[currentMission].msg[i] = ' '; + + offsetX = (int)MeasureTextEx(fontMessage, SubText(missions[currentMission].msg, wordInitPosY, (i + 1) - wordInitPosY), 30, 0).x; + + messageWords[currentWord].rec.x = offsetX; + messageWords[currentWord].rec.y = offsetY; + + wordInitPosX = i + 1; + + currentWord++; + } + else if (c == '/') + { + missions[currentMission].msg[i] = '\n'; + wordInitPosY = i; + offsetY += (fontMessage.baseSize + fontMessage.baseSize/2); // raylib internal increment on line break... + } + } + + for (int i = 0; i < missions[currentMission].wordsCount; i++) + { + messageWords[i].id = -1; // Not required for message words, id is the array position + + // Recalculate words rectangles considering text offset on screen + messageWords[i].rec.x += msgOffset.x; + messageWords[i].rec.y += msgOffset.y; + + // Recalculate words rectangle considering new width height + messageWords[i].rec.x -= (texWordsAtlas.width - messageWords[i].rec.width)/2; + messageWords[i].rec.y -= ((texWordsAtlas.height / MAX_CODING_WORDS) - messageWords[i].rec.height)/2; + + //Recalculate width height + messageWords[i].rec.width = texWordsAtlas.width; + messageWords[i].rec.height = texWordsAtlas.height / MAX_CODING_WORDS; + + messageWords[i].hover = false; // Mouse hover detected + messageWords[i].picked = false; // Mouse picked + } +} + +// Gameplay Screen Update logic +void UpdateGameplayScreen(void) +{ + UpdateMusicStream(musSpy); + + for (int i = 0; i < MAX_CODING_WORDS; i++) + { + if (CheckCollisionPointRec(GetMousePosition(), words[i].rec)) + { + words[i].hover = true; + + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + { + words[i].picked = true; + PlaySound(fxGrab); + } + } + else words[i].hover = false; + + + if (words[i].picked) + { + for (int j = 0; j < missions[currentMission].wordsCount; j++) + { + if (CheckCollisionPointRec(GetMousePosition(), messageWords[j].rec)) messageWords[j].hover = true; + else messageWords[j].hover = false; + } + + if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) + { + words[i].picked = false; + + for (int j = 0; j < missions[currentMission].wordsCount; j++) + { + messageWords[j].hover = false; + + if (CheckCollisionPointRec(GetMousePosition(), messageWords[j].rec)) + { + PlaySound(fxPlace); + + words[i].rec.x = messageWords[j].rec.x; + words[i].rec.y = messageWords[j].rec.y; + + if (messageWords[j].id != -1) + { + int id = messageWords[j].id; + words[id].rec = words[id].iniRec; + } + + messageWords[j].id = i; + for (int k = 0; k < missions[currentMission].wordsCount; k++) + { + if (j != k && messageWords[j].id == messageWords[k].id) + { + messageWords[k].id = -1; + break; + } + } + break; + } + else + { + PlaySound(fxLeave); + + words[i].rec = words[i].iniRec; + if (i == messageWords[j].id) messageWords[j].id = -1; + } + } + } + } + + // TODO: Move word picked with mouse + if (words[i].picked) + { + words[i].rec.x = GetMouseX() - words[i].rec.width/2; + words[i].rec.y = GetMouseY() - words[i].rec.height/2; + + // TODO: Check if label is placed in some mission word position + //if (CheckCollisionRecs(words[i].rec)) + } + else + { + //if (words[i].id != -1) + } + } + + canSend = true; + for(int j = 0; j < missions[currentMission].wordsCount; j++) + { + if(messageWords[j].id == -1) + { + canSend = false; + break; + } + } + + if (canSend && (IsKeyPressed(KEY_ENTER) || IsButtonPressed())) + { + finishScreen = true; + } +} + +// Gameplay Screen Draw logic +void DrawGameplayScreen(void) +{ + DrawTexture(texBackground, 0, 0, WHITE); + + DrawTextEx(fontMessage, missions[currentMission].msg, msgOffset, fontMessage.baseSize, 0, BLACK); + + for (int i = 0; i < missions[currentMission].wordsCount; i++) + { + Rectangle recLines = messageWords[i].rec; + DrawRectangleLines(recLines.x, recLines.y, recLines.width, recLines.height, Fade(RED, 0.35f)); + if(messageWords[i].hover) DrawRectangleRec(messageWords[i].rec, Fade(RED, 0.30f)); + DrawText(FormatText("%i", messageWords[i].id), i*25, 0, 30, RED); + } + for (int i = 0; i < MAX_CODING_WORDS; i++) + { + if (words[i].picked) DrawTextureRec(texWordsAtlas, (Rectangle){ 0, i*35, 140, 35 }, (Vector2){ words[i].rec.x, words[i].rec.y }, MAROON); + else if (words[i].hover) DrawTextureRec(texWordsAtlas, (Rectangle){ 0, i*35, 140, 35 }, (Vector2){ words[i].rec.x, words[i].rec.y }, RED); + else DrawTextureRec(texWordsAtlas, (Rectangle){ 0, i*35, 140, 35 }, (Vector2){ words[i].rec.x, words[i].rec.y }, WHITE); + } + + DrawTexturePro(texVignette, (Rectangle){0,0,texVignette.width, texVignette.height}, (Rectangle){0,0,GetScreenWidth(), GetScreenHeight()}, (Vector2){0,0}, 0, WHITE); + + if (canSend) DrawButton("enviar"); +} + +// Gameplay Screen Unload logic +void UnloadGameplayScreen(void) +{ + UnloadTexture(texBackground); + UnloadTexture(texVignette); + UnloadTexture(texWordsAtlas); + + UnloadSound(fxGrab); + UnloadSound(fxLeave); + UnloadSound(fxPlace); + + UnloadMusicStream(musSpy); + + free(missions); +} + +// Gameplay Screen should finish? +int FinishGameplayScreen(void) +{ + return finishScreen; +} diff --git a/games/transmission/screens/screen_logo.c b/games/transmission/screens/screen_logo.c new file mode 100644 index 00000000..30271ba6 --- /dev/null +++ b/games/transmission/screens/screen_logo.c @@ -0,0 +1,102 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Logo Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Logo screen global variables +static int framesCounter; +static int finishScreen; + +static Texture2D logoCW; + +static float fadeValue; +static int showLogoFrames; +static bool fadeOut; + +//---------------------------------------------------------------------------------- +// Logo Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Logo Screen Initialization logic +void InitLogoScreen(void) +{ + framesCounter = 0; + finishScreen = 0; + + logoCW = LoadTexture("resources/textures/cw_logo.png"); + + showLogoFrames = 60; + fadeValue = 0; + + fadeOut = false; +} + +// Logo Screen Update logic +void UpdateLogoScreen(void) +{ + if(!fadeOut) + { + fadeValue += 0.02f; + if(fadeValue > 1.01f) + { + fadeValue = 1.0f; + framesCounter++; + + if(framesCounter % showLogoFrames == 0) + { + fadeOut = true; + finishScreen = true; + } + } + } + + if(IsKeyPressed(KEY_ENTER)) + { + finishScreen = true; + } +} + +// Logo Screen Draw logic +void DrawLogoScreen(void) +{ + DrawTexture(logoCW, GetScreenWidth()/2 - logoCW.width/2, GetScreenHeight()/2 - logoCW.height/2, Fade(WHITE, fadeValue)); +} + +// Logo Screen Unload logic +void UnloadLogoScreen(void) +{ + UnloadTexture(logoCW); +} + +// Logo Screen should finish? +int FinishLogoScreen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/transmission/screens/screen_mission.c b/games/transmission/screens/screen_mission.c new file mode 100644 index 00000000..0f996502 --- /dev/null +++ b/games/transmission/screens/screen_mission.c @@ -0,0 +1,293 @@ +/********************************************************************************************** +* +* raylib - transmission mission +* +* +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" + +#include +#include + +#define MISSION_MAX_LENGTH 256 +#define KEYWORD_MAX_LENGTH 32 +#define MAX_LINE_CHAR 75 + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Mission screen global variables +static int framesCounter; +static int finishScreen; + +static Texture2D texBackground; + +static Texture2D texBackline; //mission_backline +static Rectangle sourceRecBackLine; +static Rectangle destRecBackLine; +static float fadeBackLine; + +static Vector2 numberPosition; +static Color numberColor; + +//static char textMission[MISSION_MAX_LENGTH]; +static Vector2 missionPosition; +static int missionSize; +static Color missionColor; +static int missionLenght; +static bool missionMaxLength; +static int missionSpeed; + +//static char textKeyword[KEYWORD_MAX_LENGTH]; +static Vector2 keywordPosition; +static Color keywordColor; + +static int showMissionWaitFrames; +static int showNumberWaitFrames; +static int showKeywordWaitFrames; + +static bool startWritting; +static bool writeMission; +static bool writeNumber; +static bool writeKeyword; +static bool writeEnd; + +static bool writtingMission; + +static int blinkFrames; +static bool blinkKeyWord = true; + +static bool showButton = false; + +static Mission *missions = NULL; + +static Sound fxTransmit; +static Music musMission; + +//---------------------------------------------------------------------------------- +// Mission Screen Functions Definition +//---------------------------------------------------------------------------------- +static void WriteMissionText(); +static void EndWritting(); +static void BlinkKeyword(); + +// Mission Screen Initialization logic +void InitMissionScreen(void) +{ + framesCounter = 0; + finishScreen = 0; + + fadeButton = 0.80f; + + texBackground = LoadTexture("resources/textures/mission_background.png"); + + texBackline = LoadTexture("resources/textures/mission_backline.png"); + sourceRecBackLine = (Rectangle){0,0,GetScreenWidth(), texBackline.height}; + destRecBackLine = (Rectangle){0,0,sourceRecBackLine.width, sourceRecBackLine.height}; + fadeBackLine = 0; + + fxTransmit = LoadSound("resources/audio/fx_message.ogg"); + musMission = LoadMusicStream("resources/audio/music_mission.ogg"); + + PlayMusicStream(musMission); + + // Initialize missions + missions = LoadMissions("resources/missions.txt"); + + missionMaxLength = strlen(missions[currentMission].brief); + + // Insert line breaks every MAX_LINE_CHAR + int currentLine = 1; + int i = currentLine * MAX_LINE_CHAR; + + while (i < missionMaxLength) + { + if (missions[currentMission].brief[i] == ' ') + { + missions[currentMission].brief[i] = '\n'; + currentLine++; + i = currentLine*MAX_LINE_CHAR; + } + else i++; + } + + missionSize = 30; + missionLenght = 0; + missionSpeed = 1; + + numberColor = RAYWHITE; + missionColor = LIGHTGRAY; + keywordColor = (Color){198, 49, 60, 255}; //RED + + numberPosition = (Vector2){150, 185}; + missionPosition = (Vector2){numberPosition.x, numberPosition.y + 60}; + keywordPosition = (Vector2){missionPosition.x, missionPosition.y + MeasureTextEx(fontMission, missions[currentMission].brief, missionSize, 0).y + 60}; + + startWritting = false; + writeNumber = false; + writeMission = false; + writeKeyword = false; + writeEnd = false; + + writtingMission = false; + + showNumberWaitFrames = 30; + showMissionWaitFrames = 60; + showKeywordWaitFrames = 60; + + blinkKeyWord = true; + blinkFrames = 15; + + PlaySound(fxTransmit); +} + +// Mission Screen Update logic +void UpdateMissionScreen(void) +{ + UpdateMusicStream(musMission); + + if (!writeEnd) WriteMissionText(); + else BlinkKeyword(); + + if (showButton) + { + if (IsKeyPressed(KEY_ENTER) || IsButtonPressed()) + { + if (!writeEnd) EndWritting(); + else + { + finishScreen = true; + showButton = false; + } + } + } +} + +// Mission Screen Draw logic +void DrawMissionScreen(void) +{ + // TODO: Draw MISSION screen here! + DrawTexture(texBackground, 0,0, WHITE); + DrawTexturePro(texBackline, sourceRecBackLine, destRecBackLine, (Vector2){0,0},0, Fade(WHITE, fadeBackLine)); + + if (writeNumber) DrawTextEx(fontMission, FormatText("Filtración #%02i ", currentMission + 1), numberPosition, missionSize + 10, 0, numberColor); + DrawTextEx(fontMission, SubText(missions[currentMission].brief, 0, missionLenght), missionPosition, missionSize, 0, missionColor); + if (writeKeyword && blinkKeyWord) DrawTextEx(fontMission, FormatText("Keyword: %s", missions[currentMission].key), keywordPosition, missionSize + 10, 0, keywordColor); + + if (showButton) + { + if (!writeEnd) DrawButton("saltar"); + else DrawButton("codificar"); + } +} + +// Mission Screen Unload logic +void UnloadMissionScreen(void) +{ + // TODO: Unload MISSION screen variables here! + UnloadTexture(texBackground); + UnloadTexture(texBackline); + UnloadSound(fxTransmit); + UnloadMusicStream(musMission); + free(missions); +} + +// Mission Screen should finish? +int FinishMissionScreen(void) +{ + return finishScreen; +} + +static void WriteMissionText() +{ + if(!startWritting) + { + framesCounter++; + if(framesCounter % 60 == 0) + { + framesCounter = 0; + startWritting = true; + } + } + else if(!writeNumber) + { + framesCounter++; + fadeBackLine += 0.020f; + if(framesCounter % showNumberWaitFrames == 0) + { + framesCounter = 0; + writeNumber = true; + showButton = true; + } + } + else if(!writeMission) + { + framesCounter ++; + if(framesCounter % showMissionWaitFrames == 0) + { + framesCounter = 0; + writeMission = true; + writtingMission = true; + } + } + else if(writeMission && writtingMission) + { + framesCounter++; + if(framesCounter % missionSpeed == 0) + { + framesCounter = 0; + missionLenght++; + + if(missionLenght == missionMaxLength) + { + writtingMission = false; + } + } + } + else if(!writeKeyword) + { + framesCounter++; + if(framesCounter % showKeywordWaitFrames == 0) + { + framesCounter = 0; + writeKeyword = true; + writeEnd = true; + } + } +} +static void EndWritting() +{ + writeEnd = true; + writeKeyword = true; + writeNumber = true; + missionLenght = missionMaxLength; +} +static void BlinkKeyword() +{ + framesCounter++; + if(framesCounter % blinkFrames == 0) + { + framesCounter = 0; + blinkKeyWord = !blinkKeyWord; + } +} diff --git a/games/transmission/screens/screen_title.c b/games/transmission/screens/screen_title.c new file mode 100644 index 00000000..dc062069 --- /dev/null +++ b/games/transmission/screens/screen_title.c @@ -0,0 +1,168 @@ +/********************************************************************************************** +* +* raylib - transmission mission +* +* +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#include "raylib.h" +#include "screens.h" + +#include + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Title screen global variables +static int framesCounter; +static int finishScreen; + +static Texture2D texBackground; +static SpriteFont fontTitle; +static Sound fxTyping; + +static float titleSize; +static Vector2 transmissionPosition; +static Vector2 missionPositon; + +static const char textTitle[20] = "transmissionmission"; + +static Color titleColor; +static int speedText; + +static int transmissionLenght; +static int missionLenght; +static int transmissionMaxLenght; +static int missionMaxLenght; + +static bool writeTransmission; +static bool writeMission; +static bool writeEnd; + +//---------------------------------------------------------------------------------- +// Title Screen Functions Definition +//---------------------------------------------------------------------------------- +static void MissionScreen(); + +// Title Screen Initialization logic +void InitTitleScreen(void) +{ + // TODO: Initialize TITLE screen variables here! + framesCounter = 0; + finishScreen = 0; + + texBackground = LoadTexture("resources/textures/title_background.png"); + fxTyping = LoadSound("resources/audio/fx_typing.ogg"); + fontTitle = LoadSpriteFontEx("resources/fonts/fontTitle.ttf", 96, 0, 0); + + titleSize = 44; + transmissionPosition = (Vector2){519, 221}; + missionPositon = (Vector2){580, 261}; + + titleColor = BLACK; + speedText = 15; + + missionLenght = 0; + transmissionLenght = 0; + + missionMaxLenght = 7; + transmissionMaxLenght = 12; + + writeTransmission = true; + writeMission = false; + writeEnd = false; + + currentMission = 0; +} + +// Title Screen Update logic +void UpdateTitleScreen(void) +{ + if (!writeEnd) + { + framesCounter ++; + + if (framesCounter%speedText == 0) + { + framesCounter = 0; + if (writeTransmission) + { + transmissionLenght++; + if (transmissionLenght == transmissionMaxLenght) + { + writeTransmission = false; + writeMission = true; + } + } + else if (writeMission) + { + missionLenght++; + if (missionLenght == missionMaxLenght) + { + writeMission = false; + writeEnd = true; + } + } + + PlaySound(fxTyping); + } + } + + if(IsButtonPressed()) + { + MissionScreen(); + } + else if (IsKeyPressed(KEY_ENTER)) MissionScreen(); +} + +// Title Screen Draw logic +void DrawTitleScreen(void) +{ + DrawTexture(texBackground, 0,0, WHITE); + DrawTextEx(fontTitle, SubText(textTitle, 0, transmissionLenght), transmissionPosition, titleSize, 0, titleColor); + DrawTextEx(fontTitle, SubText(textTitle, 12, missionLenght), missionPositon, titleSize, 0, titleColor); + + DrawButton("start"); +} + +// Title Screen Unload logic +void UnloadTitleScreen(void) +{ + UnloadTexture(texBackground); + UnloadSound(fxTyping); + UnloadSpriteFont(fontTitle); +} + +// Title Screen should finish? +int FinishTitleScreen(void) +{ + return finishScreen; +} + +static void MissionScreen() +{ + transmissionLenght = transmissionMaxLenght; + missionLenght = missionMaxLenght; + writeEnd = true; + //finishScreen = 1; // OPTIONS + finishScreen = true; // GAMEPLAY + //PlaySound(fxCoin); +} \ No newline at end of file diff --git a/games/transmission/screens/screens.h b/games/transmission/screens/screens.h new file mode 100644 index 00000000..27560d8b --- /dev/null +++ b/games/transmission/screens/screens.h @@ -0,0 +1,143 @@ +/********************************************************************************************** +* +* raylib - transmission mission +* +* Screens Functions Declarations (Init, Update, Draw, Unload) +* +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef SCREENS_H +#define SCREENS_H + +#define MAX_CODING_WORDS 12 +#define MAX_MISSION_WORDS 8 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef enum GameScreen { LOGO = 0, TITLE, MISSION, GAMEPLAY, ENDING } GameScreen; + +// Words to be coded or coding words +typedef struct Word { + int id; + Rectangle rec; + Rectangle iniRec; + bool hover; + bool picked; + char text[32]; // text +} Word; + +// Mission information +typedef struct Mission { + int id; + char brief[512]; // Mission briefing + char key[32]; // Mission keyword + char msg[256]; // Message to be coded + int wordsCount; // Number of words to coded + int sols[10]; // Solution code, depends on wordsCount +} Mission; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +GameScreen currentScreen; + +Music music; +Sound fxButton; + +//Mission *missions; + +// UI BUTTON +Rectangle recButton; +float fadeButton; +Color colorButton; +Texture2D texButton; +Vector2 textPositionButton; +int fontSizeButton; +Color textColorButton; + +int currentMission; +int totalMissions; + +SpriteFont fontMission; + +Word messageWords[MAX_MISSION_WORDS]; + +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif + +//---------------------------------------------------------------------------------- +// Transmission Functions Declaration +//---------------------------------------------------------------------------------- +bool IsButtonPressed(); +void DrawButton(const char *text); +Mission *LoadMissions(const char *fileName); + +//---------------------------------------------------------------------------------- +// Logo Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitLogoScreen(void); +void UpdateLogoScreen(void); +void DrawLogoScreen(void); +void UnloadLogoScreen(void); +int FinishLogoScreen(void); + +//---------------------------------------------------------------------------------- +// Title Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitTitleScreen(void); +void UpdateTitleScreen(void); +void DrawTitleScreen(void); +void UnloadTitleScreen(void); +int FinishTitleScreen(void); + +//---------------------------------------------------------------------------------- +// Mission Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitMissionScreen(void); +void UpdateMissionScreen(void); +void DrawMissionScreen(void); +void UnloadMissionScreen(void); +int FinishMissionScreen(void); + +//---------------------------------------------------------------------------------- +// Gameplay Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitGameplayScreen(void); +void UpdateGameplayScreen(void); +void DrawGameplayScreen(void); +void UnloadGameplayScreen(void); +int FinishGameplayScreen(void); + +//---------------------------------------------------------------------------------- +// Ending Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitEndingScreen(void); +void UpdateEndingScreen(void); +void DrawEndingScreen(void); +void UnloadEndingScreen(void); +int FinishEndingScreen(void); + +#ifdef __cplusplus +} +#endif + +#endif // SCREENS_H \ No newline at end of file diff --git a/games/transmission/transmission.c b/games/transmission/transmission.c new file mode 100644 index 00000000..a508b5d2 --- /dev/null +++ b/games/transmission/transmission.c @@ -0,0 +1,465 @@ +/******************************************************************************************* +* +* raylib - transmission mission +* +* Code and transmit the right message +* +* This game has been created using raylib (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" +#include "screens/screens.h" // NOTE: Defines global variable: currentScreen + +#include +#include + +#if defined(PLATFORM_ANDROID) + #include "android_native_app_glue.h" +#endif + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- +const int screenWidth = 1280; +const int screenHeight = 720; + +// Required variables to manage screen transitions (fade-in, fade-out) +static float transAlpha = 0.0f; +static bool onTransition = false; +static bool transFadeOut = false; +static int transFromScreen = -1; +static int transToScreen = -1; + +// NOTE: Some global variables that require to be visible for all screens, +// are defined in screens.h (i.e. currentScreen) + +//---------------------------------------------------------------------------------- +// Local Functions Declaration +//---------------------------------------------------------------------------------- +static void ChangeToScreen(int screen); // No transition effect + +static void TransitionToScreen(int screen); +static void UpdateTransition(void); +static void DrawTransition(void); + +static void UpdateDrawFrame(void); // Update and Draw one frame + +//---------------------------------------------------------------------------------- +// Main entry point +//---------------------------------------------------------------------------------- +#if defined(PLATFORM_ANDROID) +void android_main(struct android_app *app) +#else +int main(void) +#endif +{ + // Initialization + //--------------------------------------------------------- +#if defined(PLATFORM_ANDROID) + InitWindow(screenWidth, screenHeight, app); +#else + SetConfigFlags(FLAG_SHOW_LOGO); // | FLAG_FULLSCREEN_MODE); + InitWindow(screenWidth, screenHeight, "raylib game - transmission mission"); +#endif + + // Global data loading (assets that must be available in all screens, i.e. fonts) + InitAudioDevice(); + + music = LoadMusicStream("resources/audio/music_title.ogg"); + fxButton = LoadSound("resources/audio/fx_newspaper.ogg"); + + SetMusicVolume(music, 1.0f); + PlayMusicStream(music); + + fontMission = LoadSpriteFontEx("resources/fonts/traveling_typewriter.ttf", 64, 250, 0); + texButton = LoadTexture("resources/textures/title_ribbon.png"); + + // UI BUTTON + recButton.width = texButton.width; + recButton.height = texButton.height; + recButton.x = screenWidth - recButton.width; + recButton.y = screenHeight - recButton.height - 50; + fadeButton = 0.8f; + colorButton = RED; + textPositionButton = (Vector2){recButton.x + recButton.width/2, recButton.y + recButton.height/2}; + fontSizeButton = 30; + textColorButton = WHITE; + + currentMission = 0; + totalMissions = 4; + + // Setup and Init first screen + currentScreen = LOGO; + InitLogoScreen(); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + UpdateDrawFrame(); + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + + // Unload current screen data before closing + switch (currentScreen) + { + case LOGO: UnloadLogoScreen(); break; + case TITLE: UnloadTitleScreen(); break; + case MISSION: UnloadMissionScreen(); break; + case GAMEPLAY: UnloadGameplayScreen(); break; + case ENDING: UnloadEndingScreen(); break; + default: break; + } + + // Unload all global loaded data (i.e. fonts) here! + UnloadMusicStream(music); + UnloadSound(fxButton); + + UnloadSpriteFont(fontMission); + UnloadTexture(texButton); + + CloseAudioDevice(); // Close audio context + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- +#if !defined(PLATFORM_ANDROID) + return 0; +#endif +} + +//---------------------------------------------------------------------------------- +// Module specific Functions Definition +//---------------------------------------------------------------------------------- + +// Change to next screen, no transition +static void ChangeToScreen(int screen) +{ + // Unload current screen + switch (currentScreen) + { + case LOGO: UnloadLogoScreen(); break; + case TITLE: UnloadTitleScreen(); break; + case MISSION: UnloadMissionScreen(); break; + case GAMEPLAY: UnloadGameplayScreen(); break; + case ENDING: UnloadEndingScreen(); break; + default: break; + } + + // Init next screen + switch (screen) + { + case LOGO: InitLogoScreen(); break; + case TITLE: InitTitleScreen(); break; + case MISSION: InitMissionScreen(); break; + case GAMEPLAY: InitGameplayScreen(); break; + case ENDING: InitEndingScreen(); break; + default: break; + } + + currentScreen = screen; +} + +// Define transition to next screen +static void TransitionToScreen(int screen) +{ + onTransition = true; + transFadeOut = false; + transFromScreen = currentScreen; + transToScreen = screen; + transAlpha = 0.0f; +} + +// Update transition effect +static void UpdateTransition(void) +{ + if (!transFadeOut) + { + transAlpha += 0.02f; + + // NOTE: Due to float internal representation, condition jumps on 1.0f instead of 1.05f + // For that reason we compare against 1.01f, to avoid last frame loading stop + if (transAlpha > 1.01f) + { + transAlpha = 1.0f; + + // Unload current screen + switch (transFromScreen) + { + case LOGO: UnloadLogoScreen(); break; + case TITLE: UnloadTitleScreen(); break; + case MISSION: UnloadMissionScreen(); break; + case GAMEPLAY: UnloadGameplayScreen(); break; + case ENDING: UnloadEndingScreen(); break; + default: break; + } + + // Load next screen + switch (transToScreen) + { + case LOGO: InitLogoScreen(); break; + case TITLE: InitTitleScreen(); break; + case MISSION: InitMissionScreen(); break; + case GAMEPLAY: InitGameplayScreen(); break; + case ENDING: InitEndingScreen(); break; + default: break; + } + + currentScreen = transToScreen; + + // Activate fade out effect to next loaded screen + transFadeOut = true; + } + } + else // Transition fade out logic + { + transAlpha -= 0.02f; + + if (transAlpha < -0.01f) + { + transAlpha = 0.0f; + transFadeOut = false; + onTransition = false; + transFromScreen = -1; + transToScreen = -1; + } + } +} + +// Draw transition effect (full-screen rectangle) +static void DrawTransition(void) +{ + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(BLACK, transAlpha)); +} + +// Update and draw game frame +static void UpdateDrawFrame(void) +{ + // Update + //---------------------------------------------------------------------------------- + UpdateMusicStream(music); // NOTE: Music keeps playing between screens + + if (!onTransition) + { + switch(currentScreen) + { + case LOGO: + { + UpdateLogoScreen(); + + if (FinishLogoScreen()) TransitionToScreen(TITLE); + + } break; + case TITLE: + { + UpdateTitleScreen(); + + if (FinishTitleScreen()) + { + StopMusicStream(music); + TransitionToScreen(MISSION); + } + + } break; + case MISSION: + { + UpdateMissionScreen(); + + if (FinishMissionScreen()) + { + StopMusicStream(music); + TransitionToScreen(GAMEPLAY); + } + + } break; + case GAMEPLAY: + { + UpdateGameplayScreen(); + + if (FinishGameplayScreen() == 1) TransitionToScreen(ENDING); + //else if (FinishGameplayScreen() == 2) TransitionToScreen(TITLE); + + } break; + case ENDING: + { + UpdateEndingScreen(); + + if (FinishEndingScreen() == 1) // Continue to next mission + { + TransitionToScreen(MISSION); + } + else if (FinishEndingScreen() == 2) // Replay current mission + { + PlayMusicStream(music); + TransitionToScreen(TITLE); + } + + } break; + default: break; + } + } + else UpdateTransition(); // Update transition (fade-in, fade-out) + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + switch(currentScreen) + { + case LOGO: DrawLogoScreen(); break; + case TITLE: DrawTitleScreen(); break; + case MISSION: DrawMissionScreen(); break; + case GAMEPLAY: DrawGameplayScreen(); break; + case ENDING: DrawEndingScreen(); break; + default: break; + } + + // Draw full screen rectangle in front of everything + if (onTransition) DrawTransition(); + + //DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- +} + +// Load missions from text file +Mission *LoadMissions(const char *fileName) +{ + Mission *missions = NULL; + char buffer[512]; + + int missionsCount = 0; + + FILE *misFile = fopen(fileName, "rt"); + + if (misFile == NULL) printf("[%s] Missions file could not be opened\n", fileName); + else + { + // First pass to get total missions count + while (!feof(misFile)) + { + fgets(buffer, 512, misFile); + + switch (buffer[0]) + { + case 't': sscanf(buffer, "t %i", &missionsCount); break; + default: break; + } + } + + if (missionsCount > 0) missions = (Mission *)malloc(missionsCount*sizeof(Mission)); + else return NULL; + + rewind(misFile); // Return to the beginning of the file, to read again + + int missionNum = 0; + + while (!feof(misFile)) + { + fgets(buffer, 512, misFile); + + if (missionNum < missionsCount) + { + switch (buffer[0]) + { + case 'b': + { + // New mission brief starts! + missions[missionNum].id = missionNum; + sscanf(buffer, "b %[^\n]s", missions[missionNum].brief); + } break; + case 'k': sscanf(buffer, "k %[^\n]s", missions[missionNum].key); break; + case 'm': + { + // NOTE: Message is loaded as is, needs to be processed! + sscanf(buffer, "m %[^\n]s", missions[missionNum].msg); + } break; + case 's': + { + sscanf(buffer, "s %i %i %i %i %i %i %i %i", + &missions[missionNum].sols[0], + &missions[missionNum].sols[1], + &missions[missionNum].sols[2], + &missions[missionNum].sols[3], + &missions[missionNum].sols[4], + &missions[missionNum].sols[5], + &missions[missionNum].sols[6], + &missions[missionNum].sols[7]); + + missions[missionNum].wordsCount = 0; + + for (int i = 0; i < 8; i++) + { + if (missions[missionNum].sols[i] > -1) + { + missions[missionNum].wordsCount++; + } + } + + TraceLog(LOG_WARNING, "Mission %i - Words count %i", missionNum, missions[missionNum].wordsCount); + + missionNum++; + } break; + default: break; + } + } + } + + if (missionsCount != missionNum) TraceLog(LOG_WARNING, "Missions count and loaded missions don't match!"); + } + + fclose(misFile); + + if (missions != NULL) + { + TraceLog(LOG_INFO, "Missions loaded: %i", missionsCount); + TraceLog(LOG_INFO, "Missions loaded successfully!"); + } + + return missions; +} + +bool IsButtonPressed() +{ + if (CheckCollisionPointRec(GetMousePosition(), recButton)) + { + fadeButton = 1.0f; + + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsGestureDetected(GESTURE_TAP)) + { + PlaySound(fxButton); + return true; + } + } + else fadeButton = 0.80f; + + return false; +} + +void DrawButton(const char *text) +{ + //DrawRectangleRec(recButton, Fade(colorButton, fadeButton)); + DrawTexturePro(texButton, (Rectangle){0,0,texButton.width, texButton.height}, recButton, (Vector2){0,0},0, Fade(WHITE, fadeButton)); + Vector2 measure = MeasureTextEx(fontMission, text, fontSizeButton, 0); + Vector2 textPos = {textPositionButton.x - measure.x/2 + 10, textPositionButton.y - measure.y/2 - 10}; + DrawTextEx(fontMission, text, textPos , fontSizeButton, 0, textColorButton); +} \ No newline at end of file