├── .gitignore ├── 01statements.rpy ├── LICENSE ├── README.md ├── docs ├── .readthedocs.yaml ├── Makefile ├── __pycache__ │ ├── keywords.cpython-311.pyc │ ├── keywords.cpython-39.pyc │ ├── renpydoc.cpython-311.pyc │ └── renpydoc.cpython-39.pyc ├── assets │ ├── phone_calendars_screen.png │ ├── phone_call_history_screen.png │ ├── phone_call_screen.png │ ├── phone_contacts_screen.png │ ├── phone_discussion_screen.png │ └── phone_screen.png ├── audio.rst ├── built_in_screens.rst ├── calendars.rst ├── call_history.rst ├── changelog.rst ├── characters.rst ├── click_effects.rst ├── conf.py ├── config.rst ├── contacts.rst ├── credits.rst ├── discussion.rst ├── emojis.rst ├── functions_and_actions.rst ├── group_chats.rst ├── gui_variables.rst ├── incompatible.rst ├── index.rst ├── keywords.py ├── make.bat ├── make_your_own_app.rst ├── phone_calls.rst ├── renpydoc.py ├── requirements.txt └── system.rst ├── phone ├── 01main.rpy ├── apps │ ├── app_base.rpy │ ├── applications.rpy │ ├── calendar │ │ └── calendar.rpy │ ├── call_history │ │ └── call_history.rpy │ ├── calls │ │ ├── call_functions.rpy │ │ ├── call_screen.rpy │ │ ├── quick_menu.rpy │ │ └── say.rpy │ ├── contacts │ │ └── contacts.rpy │ └── discussion │ │ ├── audio_messages.rpy │ │ ├── discussion.rpy │ │ ├── discussion_screens.rpy │ │ ├── group_chats.rpy │ │ └── typing.rpy ├── assets │ ├── Aller_Rg.ttf │ ├── JetBrainsMono-ExtraBold.ttf │ ├── JetBrainsMono-Regular.ttf │ ├── Metropolis-Regular.otf │ ├── airplane_icon.png │ ├── arrow_icon.png │ ├── audio_message_wave_icon.png │ ├── background.png │ ├── bluetooth_icon.png │ ├── calculator_icon.png │ ├── call_icon.png │ ├── camera_icon.png │ ├── cellular_data_icon.png │ ├── circle.png │ ├── default_icon.png │ ├── emojis │ │ ├── 2hearts.png │ │ ├── 4k.png │ │ ├── Aika.png │ │ ├── AikaEmbarassed.png │ │ ├── AikaJoy.png │ │ ├── Amelia.png │ │ ├── AmeliaBreh.png │ │ ├── AmeliaPog.png │ │ ├── AmeliaPout.png │ │ ├── AmeliaTheRock.png │ │ ├── AmeliaUwaaa.png │ │ ├── Ellen.png │ │ ├── EllenBruh.png │ │ ├── EllenPog.png │ │ ├── EllenPout.png │ │ ├── EllenScream.png │ │ ├── Kaito.png │ │ ├── KaitoCrazy.png │ │ ├── KaitoPunchingBag.png │ │ ├── KaitoSorry.png │ │ ├── KaitoSurprised.png │ │ ├── Melody.png │ │ ├── MelodyClown.png │ │ ├── MelodyCryingAboutIt.png │ │ ├── MelodyPout.png │ │ ├── MelodySmug.png │ │ ├── MelodyTeehee.png │ │ ├── MelodyThink.png │ │ ├── MelodyUwU.png │ │ ├── MelodyUwaaa.png │ │ ├── andioop.png │ │ ├── angry.png │ │ ├── animeangry.png │ │ ├── bandage.png │ │ ├── barf.png │ │ ├── blueheart.png │ │ ├── blush.png │ │ ├── book1.png │ │ ├── book2.png │ │ ├── book3.png │ │ ├── book4.png │ │ ├── book5.png │ │ ├── book6.png │ │ ├── books.png │ │ ├── brownheart.png │ │ ├── bruh.png │ │ ├── brush.png │ │ ├── bull.png │ │ ├── call.png │ │ ├── callme.png │ │ ├── cap.png │ │ ├── clock.png │ │ ├── clouds.png │ │ ├── clown.png │ │ ├── cold.png │ │ ├── cookie.png │ │ ├── cowboy.png │ │ ├── crazy.png │ │ ├── cross.png │ │ ├── crown.png │ │ ├── cry.png │ │ ├── darkheart.png │ │ ├── dead.png │ │ ├── depress.png │ │ ├── disguise.png │ │ ├── dizzy.png │ │ ├── donut.png │ │ ├── drool.png │ │ ├── drop.png │ │ ├── ear.png │ │ ├── eggplant.png │ │ ├── ehehe.png │ │ ├── ehh.png │ │ ├── exhale.png │ │ ├── eye.png │ │ ├── eyes.png │ │ ├── eyesclosedsmile.png │ │ ├── fire.png │ │ ├── fist.png │ │ ├── fistl.png │ │ ├── fistr.png │ │ ├── fistup.png │ │ ├── flag.png │ │ ├── food.png │ │ ├── fuck.png │ │ ├── fuckyou.png │ │ ├── goblin.png │ │ ├── grab.png │ │ ├── grave.png │ │ ├── greenheart.png │ │ ├── guilty.png │ │ ├── halo.png │ │ ├── hand1.png │ │ ├── hand2.png │ │ ├── hands.png │ │ ├── happy1.png │ │ ├── happy2.png │ │ ├── happy3.png │ │ ├── headphones.png │ │ ├── heart.png │ │ ├── hearteyes.png │ │ ├── hearthand.png │ │ ├── hearts.png │ │ ├── heartshine.png │ │ ├── hey.png │ │ ├── hiding.png │ │ ├── highfive.png │ │ ├── hold.png │ │ ├── hot.png │ │ ├── hug.png │ │ ├── ididit.png │ │ ├── imp.png │ │ ├── italian.png │ │ ├── kill.png │ │ ├── kiss.png │ │ ├── laugh.png │ │ ├── lipbite.png │ │ ├── lips.png │ │ ├── mask.png │ │ ├── meh1.png │ │ ├── meh2.png │ │ ├── melt.png │ │ ├── mindblown.png │ │ ├── moan1.png │ │ ├── moan2.png │ │ ├── money.png │ │ ├── moon.png │ │ ├── morning.png │ │ ├── music1.png │ │ ├── music2.png │ │ ├── nerd.png │ │ ├── nomouth.png │ │ ├── nose.png │ │ ├── nut.png │ │ ├── ok.png │ │ ├── okay.png │ │ ├── oop.png │ │ ├── openbook.png │ │ ├── orangeheart.png │ │ ├── palms.png │ │ ├── party.png │ │ ├── peace.png │ │ ├── peach.png │ │ ├── peekaboo.png │ │ ├── pen1.png │ │ ├── pen2.png │ │ ├── pen3.png │ │ ├── pencil.png │ │ ├── piano.png │ │ ├── pinch.png │ │ ├── plead.png │ │ ├── plsno1.png │ │ ├── plsno2.png │ │ ├── poems.png │ │ ├── pointl.png │ │ ├── pointr.png │ │ ├── pointup.png │ │ ├── pointupagain.png │ │ ├── pray.png │ │ ├── proud.png │ │ ├── pucker1.png │ │ ├── pucker2.png │ │ ├── pucker3.png │ │ ├── purpleheart.png │ │ ├── rain.png │ │ ├── raisedeyebrow.png │ │ ├── redangry.png │ │ ├── regret.png │ │ ├── research.png │ │ ├── rock1.png │ │ ├── rock2.png │ │ ├── rollseyes1.png │ │ ├── rollseyes2.png │ │ ├── sad1.png │ │ ├── sad2.png │ │ ├── sad3.png │ │ ├── salute.png │ │ ├── shake.png │ │ ├── shakel.png │ │ ├── shaker.png │ │ ├── shh.png │ │ ├── shock.png │ │ ├── shook.png │ │ ├── sick.png │ │ ├── skull1.png │ │ ├── skull2.png │ │ ├── sleep.png │ │ ├── smile.png │ │ ├── sneeze.png │ │ ├── snooty.png │ │ ├── snooze.png │ │ ├── sob.png │ │ ├── sorry1.png │ │ ├── sorry2.png │ │ ├── star.png │ │ ├── stareyes.png │ │ ├── strong.png │ │ ├── sun.png │ │ ├── sunglasses.png │ │ ├── surprise.png │ │ ├── talleyeshappy.png │ │ ├── tasty.png │ │ ├── think.png │ │ ├── thumbsdown.png │ │ ├── thumbsup.png │ │ ├── tongue.png │ │ ├── tonguewink.png │ │ ├── tonguexd.png │ │ ├── uhoh.png │ │ ├── unimpressed.png │ │ ├── upsidedown.png │ │ ├── veryworried.png │ │ ├── wave.png │ │ ├── wet.png │ │ ├── whiteheart.png │ │ ├── why.png │ │ ├── wink.png │ │ ├── worried1.png │ │ ├── worried2.png │ │ ├── writing.png │ │ ├── wrong.png │ │ ├── xd1.png │ │ ├── xd2.png │ │ ├── xd3.png │ │ ├── yawn.png │ │ ├── yellowheart.png │ │ ├── you.png │ │ ├── zipped.png │ │ └── zzz.png │ ├── flashlight_icon.png │ ├── hang_up.png │ ├── mc_icon.png │ ├── message_icon.png │ ├── monika_icon.png │ ├── moon_icon.png │ ├── natsuki_icon.png │ ├── pause_icon.png │ ├── play_icon.png │ ├── quick_menu_afm_idle.png │ ├── quick_menu_afm_selected.png │ ├── quick_menu_history_idle.png │ ├── quick_menu_history_selected.png │ ├── quick_menu_load_idle.png │ ├── quick_menu_load_selected.png │ ├── quick_menu_save_idle.png │ ├── quick_menu_save_selected.png │ ├── quick_menu_settings_idle.png │ ├── quick_menu_settings_selected.png │ ├── quick_menu_skip_idle.png │ ├── quick_menu_skip_selected.png │ ├── rotation_locked_icon.png │ ├── rotation_unlocked_icon.png │ ├── sayori_icon.png │ ├── screen_mirroring_icon.png │ ├── status_bar_battery_empty.png │ ├── status_bar_battery_full.png │ ├── status_bar_battery_half.png │ ├── status_bar_battery_nine_tenth.png │ ├── status_bar_battery_one_fourth.png │ ├── status_bar_battery_three_fourth.png │ ├── sun_icon.png │ ├── timer_icon.png │ ├── volume_icon_0.png │ ├── volume_icon_1.png │ ├── volume_icon_2.png │ ├── wifi_icon.png │ └── yuri_icon.png ├── characters.rpy ├── config.rpy ├── definitions │ └── 01definitions.rpy ├── emojis.rpy ├── overlay │ ├── click_effects.rpy │ └── status_bar.rpy └── system.rpy └── phone_stuff.rpy /.gitignore: -------------------------------------------------------------------------------- 1 | *.rpyc 2 | 3 | gui.rpy 4 | screens.rpy 5 | options.rpy 6 | script.rpy 7 | 8 | saves/ 9 | tl/ 10 | cache/ 11 | gui/ 12 | audio/ 13 | images/ 14 | saves/ 15 | mod_assets/ 16 | .vscode/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Elckarow 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A Ren'Py 7.4.9+ phone framework inspired by the phone used in the DDLC mod, Doki Doki Exit Music Redux. 2 | 3 | Credit elckarow (formerly Elckarow#8399) [Official documentation can be found here](https://better-emr-phone.readthedocs.io/en/stable/). 4 | 5 | This framework was originally intended for DDLC modding. If you are not making a DDLC mod, you are not allowed to use MC's, Natsuki's, Sayori's, Monika's and Yuri's phone icon. 6 | 7 | ![](https://github.com/Elckarow/Better-EMR-Phone/assets/101005497/63bda61b-ea12-436f-bf00-078b6bc85851) 8 | 9 | ![](https://github.com/Elckarow/Better-EMR-Phone/assets/101005497/6f6f3f7d-1a74-40fd-9b24-2310221f381b) 10 | 11 | ![](https://github.com/Elckarow/Better-EMR-Phone/assets/101005497/b7586874-8919-4888-a31d-53006e7426dd) 12 | 13 | --- 14 | 15 | # How to setup? 16 | 17 | - Download the latest release 18 | - Copy/Paste the `phone` folder, `01statements.rpy` and `phone_stuff.rpy` into your `game` folder. 19 | - (if you change the location of the `phone` folder, make sure to also change `phone.config.basedir`) 20 | - Launch your game and call either the label `phone_discussion_test` or `phone_call_test`. 21 | - It works? Perfect! 22 | -------------------------------------------------------------------------------- /docs/.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | # Required 5 | version: 2 6 | 7 | # Build documentation in the docs/ directory with Sphinx 8 | sphinx: 9 | configuration: docs/conf.py 10 | 11 | formats: 12 | - pdf 13 | 14 | build: 15 | os: ubuntu-22.04 16 | tools: 17 | python: "3.11" 18 | 19 | python: 20 | install: 21 | - requirements: docs/requirements.txt -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/__pycache__/keywords.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/docs/__pycache__/keywords.cpython-311.pyc -------------------------------------------------------------------------------- /docs/__pycache__/keywords.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/docs/__pycache__/keywords.cpython-39.pyc -------------------------------------------------------------------------------- /docs/__pycache__/renpydoc.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/docs/__pycache__/renpydoc.cpython-311.pyc -------------------------------------------------------------------------------- /docs/__pycache__/renpydoc.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/docs/__pycache__/renpydoc.cpython-39.pyc -------------------------------------------------------------------------------- /docs/assets/phone_calendars_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/docs/assets/phone_calendars_screen.png -------------------------------------------------------------------------------- /docs/assets/phone_call_history_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/docs/assets/phone_call_history_screen.png -------------------------------------------------------------------------------- /docs/assets/phone_call_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/docs/assets/phone_call_screen.png -------------------------------------------------------------------------------- /docs/assets/phone_contacts_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/docs/assets/phone_contacts_screen.png -------------------------------------------------------------------------------- /docs/assets/phone_discussion_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/docs/assets/phone_discussion_screen.png -------------------------------------------------------------------------------- /docs/assets/phone_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/docs/assets/phone_screen.png -------------------------------------------------------------------------------- /docs/audio.rst: -------------------------------------------------------------------------------- 1 | Audio 2 | ===== 3 | 4 | This framework includes a custom audio mixer ``phone``, on which the ``phone_music`` channel has been registered. 5 | Not much you can do with it right now though... -------------------------------------------------------------------------------- /docs/built_in_screens.rst: -------------------------------------------------------------------------------- 1 | Built-in Screens 2 | ================ 3 | 4 | *This framework comes with its set of built-in screens.* 5 | 6 | ``phone()`` 7 | 8 | .. image:: assets/phone_screen.png 9 | 10 | ``phone_contacts()`` 11 | 12 | .. image:: assets/phone_contacts_screen.png 13 | 14 | ``phone_call_history()`` 15 | 16 | .. image:: assets/phone_call_history_screen.png 17 | 18 | ``phone_calendars()`` 19 | 20 | .. image:: assets/phone_calendars_screen.png 21 | 22 | ``phone_call(video=False)`` *(used during phone calls)* 23 | 24 | .. image:: assets/phone_call_screen.png 25 | 26 | ``phone_discussion()`` *(used during phone discussions)* 27 | 28 | .. image:: assets/phone_discussion_screen.png 29 | -------------------------------------------------------------------------------- /docs/calendars.rst: -------------------------------------------------------------------------------- 1 | Calendars 2 | ========= 3 | 4 | *This one requires a bit more explaination.* 5 | 6 | Loops over the list of calendars saved at ``phone.data[store.pov_key]["calendars"]`` and displays them. 7 | A day passed is rendered with a gray background. 8 | A day that has a description has a ``?`` added in the top right. 9 | 10 | Uses the ``phone_calendars`` screen. 11 | 12 | The ``Calendar`` class 13 | ---------------------- 14 | 15 | *The following functions, variables and classes are defined in the* **phone.calendar** *namespace.* 16 | 17 | ``class Calendar(calendar.Calendar)`` 18 | 19 | ``def __init__(self, month, year=2017, first_day=_default_first_day)`` 20 | 21 | * ``month`` A valid month from 1-12. 22 | * ``year`` An integer. 23 | * ``first_day`` An integer, one of the day constants described below. 24 | 25 | ``def is_day_passed(self, day)`` 26 | Returns whether the day ``day`` of this calendar is passed, compared to ``phone.system.get_date``. ``day`` has to be a valid day (from 1 to whatever the last day is). 27 | 28 | ``def lenght(self, offsets=False)`` 29 | If ``offsets`` is false, returns the number of days. If true, also returns the number of "out of range" days (take the 2023 June calendar for instance, the first 4 days and the last day are considered "out of range"). 30 | 31 | ``def get_week_days(self)`` 32 | Returns an generator iterating over the days of the week (that are strings, so ``"Monday"``, ``"Tuesday"``, ``etc...``). 33 | 34 | These objects are *iterable*. Each iteration will either return ``None`` if it's an "out of range" day or will return an object that has the following fields: 35 | 36 | * ``day`` The number of the day. Read-only. 37 | * ``description`` If not ``None``, a string. 38 | 39 | The dunder method ``__getitem__`` is also defined. It takes an integer, a valid day, and will return an object as described above, or raise an ``IndexError`` if it's not a valid day (``my_calendar[1]`` will return the first day object, ``my_calendar[0]`` will raise an ``IndexError``). 40 | 41 | Functions and Variables 42 | ----------------------- 43 | 44 | ``days = (...)`` 45 | A tuple containing strings corresponding to the week days name. The strings are flagged as translatable. 46 | 47 | ``months = (...)`` 48 | A tuple containing strings corresponding to the months name (similar to ``calendar.month_name``, it follows normal convention of January being month number 1, so it has a length of 13 and ``months[0]`` is the empty string). The strings are flagged as translatable. 49 | 50 | The constants ``MONDAY``, ``TUESDAY``, ``WEDNESDAY``, ``THURSDAY``, ``FRIDAY``, ``SATURDAY``, ``SUNDAY`` all represent a week day. 51 | 52 | ``def get_week_days(first_day=_default_first_day)`` 53 | Returns an generator iterating over the days of the week (that are strings, so ``"Monday"``, ``"Tuesday"``, ``etc...``). 54 | 55 | ``def day_name(year, month, day)`` 56 | Returns the day name of the corresponding date. 57 | 58 | ``def add_calendar(year, month, key=None, first_day=SUNDDAY)`` 59 | Creates and adds a calendar to the list of calendars for the ``*character*`` ``key``. 60 | 61 | ``def add_calendar_to_all_characters(year, month, first_day=SUNDAY)`` 62 | Same as above but for every ``*character*`` known at execution time. 63 | 64 | ``def get_calendar(year, month, key=None)`` 65 | Returns the calendar for the ``*character*`` ``key`` that has the corresponding year and month number. ``None`` is returned if no such calendar was found. -------------------------------------------------------------------------------- /docs/call_history.rst: -------------------------------------------------------------------------------- 1 | Call History 2 | ============ 3 | 4 | Not much to say about this one. 5 | Loops over the list of saved call at ``phone.data[store.pov_key]["call_history"]`` and display them alongside the duration if one was given. 6 | 7 | Uses the ``phone_call_hisory`` screen. 8 | 9 | *That's it.* -------------------------------------------------------------------------------- /docs/changelog.rst: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | *See* ``Incompatible Changes`` *for additional information.* 5 | 6 | A list of all the changes throughout the versions, starting from 3.0.0. 7 | 8 | 3.3.0 9 | ----- 10 | 11 | * A new function ``phone.discussion.set_up_group_chat``. 12 | 13 | 3.2.2 14 | ----- 15 | 16 | * The ``phone call`` statement can now take a ``nosave`` clause. 17 | * Added new default emojis. 18 | * 4 new functions ``phone.asset``, ``phone.path_join``, ``phone.short_name`` and ``phone.execute_default``. 19 | * ``GroupChat.short_name`` and ``Character.short_name`` are now deprecated. See the new ``phone.short_name`` function. 20 | * Reworked a bit the ``phone_contacts`` screen. 21 | * Reset the yadjustment when starting a phone discussion. 22 | * 7 new phone config variables. 23 | * Fixed an issue where changes applied to a calendar would persist when going back to the main menu. 24 | 25 | 3.2.1 26 | ----- 27 | 28 | * Checks for the correct version before appending to ``config.detached_layers``. 29 | 30 | 3.2.0 31 | ----- 32 | 33 | * Group chats can now be transient. A transient group chat will be cleared once a discussion is over. 34 | * Added video phone calls. 35 | * A battery level of 0% will now display an empty battery (as it should). 36 | * Added the ``pause`` phone discussion statement. 37 | * Can now start a phone discussion when another discussion is going on. 38 | 39 | 3.1.1 40 | ----- 41 | 42 | * Clearer error messages when a group chat / phone character isn't defined. 43 | * Document some GUI variables. 44 | * Phone definitions will now work on an already existing save. Before, if you had a save where no group chat was defined (this is just an example), that you created a group chat, and then loaded that save, the group chat wouldn't be registered. This change replicates the behavior of the ``default`` statement, allowing creators to, for instance, add this framework to an already released game. After loading the save, rollback will be blocked in such cases. 45 | * Fixed an issue where running ``PhoneMenu`` during an interaction would block the player from advancing after returning. 46 | 47 | 3.1.0 48 | ----- 49 | 50 | * Improved lint. 51 | * ``phone.discussion.date`` and ``phone.discussion.register_date`` now accept ``None`` and ``True`` values (before, only the ``date`` phone statement could use ``None`` values). 52 | * ``phone.discussion.date`` and ``phone.discussion.register_date`` now accept two new arguments: ``second`` and ``auto``. 53 | * The ``image`` phone statement and ``phone.discussion.image`` can now take any displayable. 54 | * Fixed an issue with ``gui.phone_message_label_null_height``. 55 | * Added ``phone.config.discussion_callbacks``. 56 | 57 | 3.0.3 58 | ----- 59 | 60 | * Fixed the ``calendar`` app layout. 61 | 62 | 3.0.2 63 | ----- 64 | 65 | * Fixed the ``pass`` phone discussion statement. 66 | 67 | 3.0.1 68 | ----- 69 | 70 | * Phone messages now respect the ``delay`` property. 71 | * Phone labels can now accept ``None`` values. 72 | * The audio icon in the status bar now uses ``preferences.get_mixer`` on 7.6/8.1+ and ``preferences.get_volume`` on other Ren'Py versions. 73 | * A new function has been introduced to the ``phone.character`` namespace: ``get_all()``. 74 | * A new function has been introduced to the ``phone.group_chat`` namespace: ``get_all()``. 75 | 76 | 3.0.0 77 | ----- 78 | 79 | * None -------------------------------------------------------------------------------- /docs/characters.rst: -------------------------------------------------------------------------------- 1 | Characters 2 | ========== 3 | 4 | *The following functions and classes are defined in the* **phone.character** *namespace.* 5 | 6 | The phone ``Character`` class 7 | ----------------------------- 8 | 9 | ``class Character(object)`` 10 | Not to confuse with Ren'Py's ``Character`` objects (we're in the ``phone.character`` namespace remember), these objects form the core of the framework. 11 | 12 | When talking about a phone ``Character`` object, I will (most of the time) use this notation: 13 | 14 | ``*character*`` 15 | 16 | which means the phone ``Character`` object itself or its ``key`` (you'll see what it is just below). 17 | 18 | ``def __init__(self, name, icon, key, cps, color)`` 19 | 20 | * ``name``: a string, the name of the character. 21 | * ``icon``: a displayable. 22 | * ``key``: any hashable object that is not ``None``. this must be a unique object proper to this phone ``Character`` object. 23 | * ``cps``: an integer. 24 | * ``color``: any valid color value. 25 | 26 | Once the object has been created, the ``name``, ``icon`` and ``cps`` fields can be safely changed. The ``key`` and ``color`` fields are read-only. 27 | 28 | ``def get_textbox(self)`` 29 | Returns a solid with rounded corners of the character's color and the radius given by ``phone.config.textbox_radius``. 30 | 31 | ``def is_pov(self)`` *(property)* 32 | Returns whether the character's key is equal to the store variable ``store.pov_key``. 33 | 34 | ``def get_typing_delay(self, message, substitute=True)`` 35 | Returns a number of second this character would be typing out ``message`` (a string). If ``substitute`` is true, text substitution occurs before computing the time. 36 | 37 | These objects are *hashable* (their key will be hashed). 38 | 39 | **When creating a phone** ``Character`` **object, you must use** ``default`` **and not** ``define`` **.** 40 | 41 | Functions 42 | --------- 43 | 44 | ``def character(x)`` 45 | Returns the ``*character*`` ``x``. If ``x`` is a phone ``Character``, returns it, otherwise it is taken to be the key to a phone ``Character`` object and will return that object, or raise ``KeyError`` if no phone ``Character`` object has a key like this (if ``None`` is passed, ``store.pov_key`` is used). 46 | 47 | ``def has_character(key)`` 48 | Returns true if there is a phone ``Character`` with the key ``key``, or fals if there is not. 49 | 50 | ``def get_textbox(color)`` 51 | Returns a solid with rounded corners of color ``color`` and the radius given by ``phone.config.textbox_radius``. 52 | 53 | ``def get_all()`` 54 | Returns a list of all phone ``Character`` objects defined. 55 | 56 | Example 57 | ------- 58 | :: 59 | 60 | # default /!\ 61 | default p_eileen = phone.character.Character("Eileen", phone.asset("default_icon.png"), "eileen", 20, "#fff") 62 | -------------------------------------------------------------------------------- /docs/click_effects.rst: -------------------------------------------------------------------------------- 1 | Click effects 2 | ============= 3 | 4 | The framework comes with a built-in click effects that shows a displayable whenever a click/drag/release occurs. 5 | 6 | It uses three variables 7 | 8 | * ``phone_on_click_effect`` 9 | * ``phone_on_drag_effect`` 10 | * ``phone_on_release_effect`` 11 | 12 | which are, if not ``None``, a 2-tuple containing a displayable and a float. 13 | 14 | Whenever the corresponding mouse event occurs 15 | 16 | * a left/right click for ``phone_on_click_effect`` 17 | * moving the mouse while holding click for ``phone_on_drag_effect`` 18 | * releasing a click for ``phone_on_release_effect`` 19 | 20 | the corresponding displayable will be added to the screen and then hidden after the amout of time passed as second element of the tuple. 21 | 22 | say you have this :: 23 | 24 | define phone_on_click_effect = (Solid("#f00", xysize=(50, 50)), 2) 25 | 26 | left/right clicking will add a 50x50 red square to the screen that will be hidden after 2 seconds. -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | 16 | sys.path.append(os.path.abspath('.')) 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = 'Better EMR Phone Documentation' 21 | copyright = '2023, Elckarow' 22 | author = 'Elckarow' 23 | 24 | # The full version, including alpha/beta/rc tags 25 | release = 'v3.2.0' 26 | 27 | # -- General configuration --------------------------------------------------- 28 | 29 | # Add any Sphinx extension module names here, as strings. They can be 30 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 31 | # ones. 32 | extensions = [ 33 | 'sphinx.ext.todo', 34 | 'sphinx.ext.extlinks', 35 | 'sphinx.ext.ifconfig', 36 | 'renpydoc', 37 | 'sphinx.ext.intersphinx', 38 | 'sphinx_rtd_theme', 39 | 'sphinx_rtd_dark_mode', 40 | ] 41 | # Add any paths that contain templates here, relative to this directory. 42 | templates_path = [ ] 43 | 44 | # The suffix(es) of source filenames. 45 | source_suffix = ".rst" 46 | 47 | # List of patterns, relative to source directory, that match files and 48 | # directories to ignore when looking for source files. 49 | # This pattern also affects html_static_path and html_extra_path. 50 | exclude_patterns = [ ] 51 | 52 | # The name of the Pygments (syntax highlighting) style to use. 53 | # pygments_style = 'sphinx' 54 | pygments_style = 'default' 55 | 56 | 57 | # -- Options for HTML output ------------------------------------------------- 58 | 59 | # The theme to use for HTML and HTML Help pages. See the documentation for 60 | # a list of builtin themes. 61 | # 62 | html_static_path = ['_static'] 63 | 64 | html_context = { 65 | 'display_github': True, 66 | 'github_user': 'Elckarow', 67 | 'github_repo': 'Better-EMR-Phone', 68 | } 69 | 70 | html_theme = "sphinx_rtd_theme" 71 | 72 | #html_theme_path = [sphinx_nervproject_theme.get_html_theme_path()] 73 | #html_theme_path = [sphinx_pdj_theme.get_html_theme_path()] 74 | # sets the darker appearence 75 | # html_theme_options = { 76 | # 'style': 'darker' 77 | # } 78 | 79 | # Add any paths that contain custom static files (such as style sheets) here, 80 | # relative to this directory. They are copied after the builtin static files, 81 | # so a file named "default.css" will overwrite the builtin "default.css". 82 | # html_static_path = ['_static'] 83 | 84 | highlight_language = "renpy" 85 | master_doc = 'index' -------------------------------------------------------------------------------- /docs/config.rst: -------------------------------------------------------------------------------- 1 | Configuration Variables 2 | ======================= 3 | 4 | *The following variables are defined in the* **phone.config** *namespace.* 5 | 6 | **This namespace is considered *constant* and should not be modified outside of init time.** 7 | 8 | ``basedir = "phone/assets/"`` 9 | A path from the game folder to the directory where the assets are located. 10 | 11 | ``overlay_screens = [...]`` 12 | A list of screen names shown above the phone screens (but still inside the phone). As the framework uses it internally, creators should ``append`` their screen name to the list rather than replacing it entirely. 13 | 14 | ``quick_menu = True`` 15 | If true, the framework's quick menu is used during phone calls. If false, the game's quick menu is used. 16 | 17 | ``enter_transition = Dissolve(0.6, time_warp=_warper.ease)`` 18 | A transition used when showing the phone. 19 | 20 | ``exit_transition = Dissolve(0.6, time_warp=_warper.ease)`` 21 | A transition used when hiding the phone. 22 | 23 | ``intra_transition = Dissolve(0.1)`` 24 | A transition used when going from a phone screen to another. 25 | 26 | ``time_format = _("%H:%M")`` 27 | A string used to format a time. Passed to ``time.strftime``. 28 | 29 | ``date_format = _("%m/%d/%Y")`` 30 | A string used to format a date. Passed to ``datetime.datetime.strftime``. 31 | 32 | ``textbox_radius = 15`` 33 | The radius of the rounded corners of the text messages' textboxes. 34 | 35 | ``call_history_length = 20`` 36 | How many phone calls we save. 37 | 38 | ``message_text_tags = set(...)`` 39 | A set of text tags that are allowed in text messages. They should not affect the text's size. 40 | 41 | ``status_bar = True`` 42 | If true, the phone uses the status bar. If false, it doesn't. 43 | 44 | ``hide_status_bar_screens = [...]`` 45 | A list of screen names. When the status bar is used, it is hidden when any of these screens are showing. 46 | 47 | ``layer_at_transforms = {...}`` 48 | A dictionary mapping a screen name to a transform or a list of transforms. When a phone screen is shown, the screen name is looked up in the map (None is used if not found), and the layer "master" is shown at those transforms using ``phone.show_layer_at``. 49 | 50 | ``applications_pages = 4`` 51 | How many "pages" of application we use in the ``phone`` screen. 52 | 53 | ``lowest_brightness = 0.3`` 54 | From 0.0 (complete darkness) to 1.0 (normal), how low can the brightness go? 55 | 56 | ``data = {...}`` 57 | A dictionnary mapping a name to a callable. Each \*character\* has an entry (their key) containing these values in the ``phone.data`` dictionnary. When the entry is created, the callables are called without arguments, and the values are set. 58 | tl;dr ``collections.defaultdict`` 59 | The following keys are documented: 60 | 61 | * ``"call_history"`` 62 | * ``"group_chats"`` 63 | * ``"background_image"`` 64 | * ``"calendars"`` 65 | * ``"applications"`` 66 | 67 | ``discussion_callbacks = [...]`` 68 | A list of functions that are called whenever a phone discussion function executes. 69 | They are called with three arguments: 70 | 71 | * the ``*group chat*`` the interaction is taking place in. 72 | * an event: 73 | 74 | * ``"start"`` is delivered at the start of the interaction. 75 | * ``"end"`` is delivered just before the data has been saved. 76 | * ``"save"`` is delivered after the data has been saved (called after the ``register_`` function associated to what's happening). 77 | 78 | * an object representing the data, which has thefollowing fields: 79 | 80 | * ``source``, the ``*character*`` that's sending the data, or ``None``. 81 | * ``type``, one of the following constants (in the ``phone.discussion`` namespace): ``TYPING``, ``TEXT``, ``IMAGE``, ``LABEL``, ``DATE``, ``MENU``, ``AUDIO``, ``VIDEO`` (if it ever gets implemented). 82 | * ``data``: 83 | 84 | * For a typing, the time to wait for. 85 | * For a text message, the text that's been formatted by ``phone.discussion.remove_text_tags``. 86 | * For an image, the displayable. 87 | * For a label, the text. 88 | * For a date, a tuple of (``month``, ``day``, ``year``, ``hours``, ``minutes``, ``seconds``). 89 | * For a menu, a list of all the captions. 90 | * For an audio, the string of the audio. 91 | * For a video, ``None``. 92 | 93 | ``video_call_layer = "phone_video_call"`` 94 | The name of the layer usied in video calls. It is appended to ``config.detached_layers`` 95 | 96 | ``video_call_layer_transform_properties = {...}`` 97 | A dict of transform properties applied to the ``Layer`` displayable (not the layer itself) used during a video call. The default dict centers the displayable and makes it fit the phone vertically. 98 | 99 | ``messages_displayed = 100`` 100 | How many messages we display at the same time. 101 | 102 | ``messages_fill_if_lower = 30`` 103 | If the next "load" of messages contains this many or less messages, add those messages to the current load. 104 | 105 | ``message_delay = 0.6`` 106 | A number of seconds added to the pause before each message. 107 | 108 | ``unread_group_chat_pov = False`` 109 | If true, a group chat's "unreadness" is determined on the pov the group chat was read in. 110 | I.e, if the group chat was read in the "mc" pov, then it won't be marked as read in the "s" pov. 111 | If false, it is determined by whether the player has opened the group chat or not. 112 | 113 | ``auto_emojis = True`` 114 | If true, will define all images found in "assets/emojis" as emojis. 115 | 116 | ``default_label_delay = 0.5`` 117 | The default value of the `delay` property for the `time` and `label` discussion statements. -------------------------------------------------------------------------------- /docs/contacts.rst: -------------------------------------------------------------------------------- 1 | Contacts 2 | ======== 3 | 4 | Loops over the group chats known to the ``*character*`` ``store.pov_key`` at ``phone.data[store.pov_key]["group_chats"]`` and, for each group chat, displays a button that, when clicked, allows the player to read the chat. 5 | 6 | Uses the ``phone_contacts`` screen. 7 | 8 | *That's it.* -------------------------------------------------------------------------------- /docs/credits.rst: -------------------------------------------------------------------------------- 1 | Credits 2 | ======= 3 | 4 | I'd like to thank to following people for their contributions: 5 | 6 | * silversnow\_\_ (MC's icon) 7 | * lameman (Quick menu icons) 8 | * negative.two (Shader code for the ``CircleDisplayable`` displayable) 9 | * calebthepianist (Renaming all the twemojis) 10 | 11 | as well as the project's contributors on GitHub: 12 | 13 | * Galo223344 14 | * MapMappening 15 | * VodkaBro 16 | * avocolado 17 | * MDHtrappy 18 | 19 | Various ressources used: 20 | 21 | * `twemojis `_ 22 | * `Wintermute's Gradient displayable `_ -------------------------------------------------------------------------------- /docs/emojis.rst: -------------------------------------------------------------------------------- 1 | Emojis 2 | ====== 3 | 4 | This framework comes with a built-in emoji system (used in text messages but I guess creators can find usage elsewhere). 5 | 6 | *The following functions are defined in the* **phone.emojis** *namespace.* 7 | 8 | **This namespace is considered *constant* and should not be modified outside of init time.** 9 | 10 | ``def add(name, emoji)`` 11 | This function adds an emoji to the list of known emojis. It take a string ``name`` (which amy only contain letters, numbers and underscores) and a displayable ``emoji``. 12 | 13 | ``def get(name)`` 14 | Returns the emoji with the name ``name``. Raises a ``KeyError`` in case the emoji wasn't found. 15 | 16 | **A custom text tag is also defined: the** ``emoji`` **text tag.** 17 | ``"This framework is {emoji=poggers}!"`` will use the ``poggers`` emoji. The displayable will be scaled up or down so that it fits in a line of text. 18 | 19 | ``def format_emoji_tag(s)`` 20 | This function formats the string ``s`` by replacing each ``emoji`` text tag with a more readable version (basically it replaces the tag with how you'd write it in discord). :: 21 | 22 | phone.emoji.format_emoji_tag("This framework is {emoji=poggers}!") 23 | >>> "This framework is :poggers:!" 24 | 25 | Default emojis include: 26 | * The most used twemojis 27 | * Some emojis from the Doki Doki Undercurrents discord server. -------------------------------------------------------------------------------- /docs/functions_and_actions.rst: -------------------------------------------------------------------------------- 1 | Functions and Actions 2 | ===================== 3 | 4 | Utility Functions 5 | ----------------- 6 | 7 | *The following functions, variables and Actions are defined in the* **phone** *namespace.* 8 | 9 | ``def format_date(month, day, year)`` 10 | Returns a formatted string using ``phone.config.date_format``. 11 | 12 | ``def format_time(hour, minute)`` 13 | Returns a formatted string using ``phone.config.time_format``. 14 | 15 | ``def show_layer_at(at_list, layer="master", camera=True, reset=False)`` 16 | A wrapper around ``renpy.show_layer_at``. If ``at_list`` is a string (or ``None``), it is looked up in ``phone.config.layer_at_transform``. The transform or list of transforms is then passed to ``renpy.show_layer_at`` along with the other parameters. 17 | 18 | ``def short_name(s, length)`` 19 | Shortens the string ``s`` after translating it. The string is sliced to ``length - 3`` and ``"..."`` is appended to it. 20 | 21 | ``def path_join(*args)`` 22 | A wrapper around ``os.path.join``, replacing backslashes if needed. 23 | 24 | ``def asset(path)`` 25 | Computes *path_join(phone.config.basedir, path)* 26 | 27 | ``def execute_default(f, id)`` 28 | Mimics the behavior of the ``default`` statement by calling ``f`` if a function with the unique value ``id`` has never been called before. 29 | The function is added to ``config.start_callbacks`` and ``config.after_load_callbacks``, and in the latter case, if the function is called, rollback will be blocked. 30 | A good *unique value*, for instance, is a tuple where the first component is a string describing what the function does, and where the remaining components are the actual unique value related to whatever the function does. 31 | For example, when calling ``phone.calendar.add_calendar`` during init phase, this function is called with the unique value ``("_phone_add_calendar", month, year, key)``, where ``month``, ``year`` and ``key`` are the values passed to ``phone.calendar.add_calendar``. 32 | 33 | ``data = {...}`` 34 | The dictionnary that's storing all of the phone's in-game data. Each ``*character*`` has an entry (their key) in this dict and will return another dictionnary as described in ``phone.config.data``. 35 | 36 | ``NoValue = ...`` 37 | A unique object that's used when no value is passed to a callable. 38 | 39 | Screen Functions and Actions 40 | ---------------------------- 41 | 42 | ``class PhoneMenu(Action)`` 43 | The framework's equivalent of the ``ShowMenu`` action. 44 | Arguments given are passed to the ``phone.call_screen`` function. 45 | 46 | ``def call_screen(_screen_name, *args, **kwargs)`` 47 | The framework's equivalent of the ``renpy.call_screen`` function. 48 | If the ``_transition`` keyword argument is passed, it's the transition ran when showing the screen. Otherwise, it's taken from ``phone.config.enter_transition`` and ``phone.config.intra_transition`. 49 | Invokes ``renpy.call_screen`` in a new context, passing all arguments and keyword arguments to it. This ensures a sort of "depths" effect (going to screen A, then screen B, then screen C, returning brings you back to screen B, and so on). 50 | 51 | ``def PhoneReturn(value=None, transition=NoValue)`` 52 | The framework's equvalent of the ``Return`` action. It should be used to return from a phone screen. 53 | 54 | ``menu = False`` 55 | Indicates whether we're in a phone menu or not. This is useful when a button is used in a phone screen that's used both in-game and through the ``PhoneMenu`` action (for instance, the ``Back`` textbutton in the ``phone_discussion`` is disabled during a phone discussion). As it is set by ``phone.call_screen``, this variable should be read-only. 56 | 57 | *The* **PhoneReturn** *and* **PhoneMenu** *actions are available in the global store. If their values are overridden during init phase, an error is raised.* -------------------------------------------------------------------------------- /docs/group_chats.rst: -------------------------------------------------------------------------------- 1 | Group Chats 2 | =========== 3 | 4 | *The following functions and classes are defined in the* **phone.group_chat** *namespace.* 5 | 6 | The ``GroupChat`` class 7 | ----------------------- 8 | 9 | ``class GroupChat(object)`` 10 | The core of the discussion part of this framework. 11 | 12 | ``def __init__(self, name, icon, key, transient=False)`` 13 | 14 | * ``name``: a string, the name of the character. 15 | * ``icon``: a displayable. 16 | * ``key``: any hashable object that is not ``None``. this must be a unique object proper to this ``phone.group_chat.GroupChat`` object. 17 | * ``transient``: a boolean. If true, the group chat is cleared once the discussion is over. 18 | 19 | Once created, the following fields can be read and safely modified: 20 | 21 | * ``name`` 22 | * ``icon`` 23 | 24 | while following fields should be read only: 25 | 26 | * ``unread`` 27 | * ``date`` 28 | * ``transient`` 29 | 30 | ``def add_character(self, char)`` 31 | Adds the ``*character*`` ``char`` to this group chat, saves the group chat in the ``*character*``'s list of known group chats, and returns the group chat. 32 | 33 | ``def remove_character(self, char)`` 34 | Removes the ``*character*`` ``char`` from this group chat, and removes the group chat from the ``*character*``'s known group chats. 35 | 36 | ``def number_of_messages_sent(self, char)`` 37 | Returns the number of messages sent by the ``*character*`` ``char``. If ``None`` is passed, returns the total number of messages sent. 38 | 39 | ``def clear(self)`` 40 | Clears the group chat's history. 41 | 42 | These objects are *hashable* (their key will be hashed). 43 | 44 | Functions 45 | --------- 46 | 47 | ``def group_chat(x)`` 48 | If ``x`` is a ``phone.group_chat.GroupChat`` object, will return that object, otherwise, the group chat with the same key will be returned, or raise a ``KeyError`` if it wasn't found. 49 | 50 | ``def has_group_chat(key)`` 51 | Returns if a group chat with the key ``key`` exists. 52 | 53 | ``def get_all()`` 54 | Returns a list of every group chats defined. 55 | 56 | Example 57 | ------- 58 | :: 59 | 60 | # default /!\ 61 | default eileen_gc = phone.group_chat.GroupChat("Eileen", phone.asset("default_icon.png"), "eileen_gc").add_character("eileen") 62 | 63 | or use the ``define`` clause of the ``init phone register`` statement. :: 64 | 65 | init phone register: 66 | define "Hello": 67 | icon "icon.png" add "eileen" key "hello" -------------------------------------------------------------------------------- /docs/gui_variables.rst: -------------------------------------------------------------------------------- 1 | GUI Variables 2 | ============= 3 | 4 | *Please note that this framework was developed on a 1280x720 project.* 5 | 6 | These variables can be found in the ``phone_stuff.rpy`` file. 7 | 8 | ``gui.phone_xsize = 389`` 9 | The width available for the phone screens. 10 | 11 | ``gui.phone_ysize = 803`` 12 | The height available for the phone screens. 13 | 14 | ``gui.phone_margin = (15, 81, 15, 94)`` 15 | Margins added to the left / top / right / bottom of the phone's available area, respectively. 16 | 17 | *If you take* **gui.phone_margin** *to be* **(l, t, r, b)** *,* **l + r + gui.phone_xsize** *and* **t + b + gui.phone_ysize** *should match the phone's background image's dimensions (the one at* **phone.config.basedir + "background.png"** *).* 18 | 19 | ``gui.phone_zoom = 0.8`` 20 | The level of zoom applied to the phone. If your project uses a different aspect ratio than 1280x720, you might want to consider modifying this variable. 21 | 22 | *Other GUI variables exist but should not be changed by creators.* -------------------------------------------------------------------------------- /docs/incompatible.rst: -------------------------------------------------------------------------------- 1 | Incompatible Changes 2 | ==================== 3 | 4 | A list of all changes that may require you to modify some of your code. 5 | 6 | 3.3.0 7 | ----- 8 | 9 | * None 10 | 11 | 3.2.2 12 | ----- 13 | 14 | * The ``phone.config`` and ``phone.emojis`` namespaces now behave the same way as renpy's ``config``. The ``default`` statement cannot be used to declare a variable in those namespaces. 15 | * The ``phone.calendar.add_calendar`` and ``phone.calendar.add_calendar_to_all_characters`` functions have had their signature changed. 16 | 17 | 3.2.1 18 | ----- 19 | 20 | * None 21 | 22 | 3.2.0 23 | ----- 24 | 25 | * The ``Quit`` button in the ``phone`` screen has been removed in place of a dismiss-like button. 26 | * The ``pass`` phone discussion statement now doesn't do anything, like a regular ``pass`` statement. To wait for a user input, see the ``pause`` phone discussion statement. 27 | 28 | 3.1.1 29 | ----- 30 | 31 | * The ``phone register`` statement can't be ran during init phase anymore. Use the ``init phone register`` statement instead. 32 | * ``auto`` can't be used anymore for the ``time`` statement in the ``init phone register`` statement. 33 | 34 | 3.1.0 35 | ----- 36 | 37 | * None 38 | 39 | 3.0.3 40 | ----- 41 | 42 | * None 43 | 44 | 3.0.2 45 | ----- 46 | 47 | * None 48 | 49 | 3.0.1 50 | ----- 51 | 52 | * None 53 | 54 | 3.0.0 55 | ----- 56 | 57 | * Functions and classes related to phone characters have been moved in the ``phone.character`` namespace. 58 | * Functions and classes related to group chats have been moved in the ``phone.group_chat`` namespace. -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to the Better EMR Phone Documentation! 2 | ============================================== 3 | 4 | **This framework is intended for Ren'Py 7.4.9+ only. Any Ren'Py version below 7.4.9 will lead to errors and unexpected behavior.** 5 | 6 | As the name indicates, the first version of this phone was first seen in the DDLC mod `Doki Doki: Exit Music REDUX `_. 7 | 8 | It was pretty good (visually that is). The back-end code was... *a bit spaghetti not gonna lie*. Since I needed a phone for my own (well not my *own* per se, I simply am the lead coder) DDLC mod `Doki Doki Undercurrents `_ (go check it out), I decided to... remake the whole thing. 9 | Took a few tries but here we are I guess. 10 | 11 | *Credit goes to Wretched Team for the original version.* 12 | 13 | **If you are not using this framework for a DDLC mod, the use of Monika's icon, Natsuki's icon, Yuri's icon, Sayori's icon and MC's icon is forbidden.** 14 | 15 | **Be sure to credit Elckarow#8399 for making this framework (or I will haunt your dreams).** 16 | 17 | .. toctree:: 18 | :maxdepth: 1 19 | 20 | characters 21 | group_chats 22 | emojis 23 | discussion 24 | phone_calls 25 | 26 | .. toctree:: 27 | :maxdepth: 1 28 | 29 | make_your_own_app 30 | contacts 31 | call_history 32 | calendars 33 | 34 | .. toctree:: 35 | :maxdepth: 1 36 | 37 | built_in_screens 38 | 39 | .. toctree:: 40 | :maxdepth: 1 41 | 42 | functions_and_actions 43 | gui_variables 44 | config 45 | system 46 | click_effects 47 | audio 48 | 49 | ---- 50 | 51 | .. toctree:: 52 | :maxdepth: 1 53 | 54 | credits 55 | changelog 56 | incompatible 57 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/make_your_own_app.rst: -------------------------------------------------------------------------------- 1 | Wanna make your own app? 2 | ======================== 3 | 4 | In order to do that, you need **two** things: 5 | 6 | * A phone screen 7 | * A ``phone.application.Application`` object (not necessary but if you want your app to appear on the ``phone`` screen then yes you need this) 8 | 9 | The ``_phone`` screen 10 | --------------------- 11 | 12 | To create a phone screen, simply ``use`` the ``_phone`` screen, intended as base for all phone screen. :: 13 | 14 | screen my_phone_screen(): 15 | use _phone(): 16 | # your screen code goes there 17 | 18 | The ``_phone`` screen has 5 parameters: 19 | 20 | * ``xpos`` The xpos of the phone. 21 | * ``ypos`` The ypos of the phone. 22 | * ``xanchor`` The xanchor of the phone. 23 | * ``yanchor`` The yanchor of the phone. 24 | * ``horizontal`` If true, the phone is displayed horizontally. If false, it is displayed vertically. 25 | 26 | Once you've coded your screen, simply call it with ``phone.call_screen`` or the ``PhoneMenu`` action and there you go! 27 | 28 | Applications 29 | ------------ 30 | 31 | If you want your app to appear on the ``phone`` screen, you need to create a ``phone.application.Application`` object and add it to your ``*character*``\s. 32 | 33 | *The following functions and classes are defined in the* **phone.application** *namespace.* 34 | 35 | ``class Application(object)`` 36 | 37 | ``def __init__(self, name, icon, action)`` 38 | 39 | * ``name`` A string. The name of the app. 40 | * ``icon`` A ``phone.application.Icon`` or ``phone.application.GradientBackground`` object. 41 | * ``action`` An action to run when clicking on the app (most of the time it's a ``PhoneMenu`` action, but any valid action works). 42 | 43 | ``def Icon(d, size=None, background=None)`` 44 | Retuns a displayable used as icon for applications. 45 | ``d`` is a displayable to add on to the icon. ``size`` is the size that displayable takes. 46 | ``background``, if not ``None``, is a ``phone.application.IconBackground`` or ``phone.application.GradientBackground`` object displayed behind ``d``. 47 | 48 | ``def GradientBackground(start_color, end_color, theta=0)`` 49 | Retuns a ``phone.application.IconBackground`` object with a ``Gradient`` as displayable. 50 | 51 | ``def IconBackground(d, **kwargs)`` 52 | Returns ``d`` with rounded corners of size ``gui.phone_application_icon_size``. 53 | 54 | Example 55 | ------- 56 | :: 57 | 58 | init python: 59 | my_app = phone.application.Application( 60 | "my application", 61 | phone.application.GradientBackground("#5bf676", "#04be25"), 62 | PhoneMenu("my_phone_screen") 63 | ) 64 | 65 | Now that you've done this, it's time to add the app to the ``*character*``\s you've defined, using those two functions. 66 | 67 | ``def add_application(app, page=0, key=None)`` 68 | Adds the application ``app`` to the known applications for ``*character*`` ``key``. Returns ``True`` if it succesfully added the app, ``False`` if it failed, or ``None`` if Ren'Py is still in init phase. 69 | 70 | ``def add_app_to_all_characters(app, page=0)`` 71 | Same as above but for every ``*character*`` known at execution time. 72 | 73 | To add the app you've created, simply :: 74 | 75 | phone.application.add_app_to_all_characters(my_app) 76 | 77 | and ta-da, your app should appear on the ``phone`` screen. 78 | 79 | Functions 80 | --------- 81 | 82 | ``def move_application(start, end, key=None)`` 83 | ``start``/``end`` are 3-tuples containing a page, a column and a row. They represent the start/end point. This function swaps the application of coordinates ``start`` with the one of coordinates ``end``. -------------------------------------------------------------------------------- /docs/phone_calls.rst: -------------------------------------------------------------------------------- 1 | Phone calls 2 | =========== 3 | 4 | *The following functions are defined in the* **phone.calls** *namespace (not* **phone.call**, *Ren'Py doesn't like me using that).* 5 | 6 | Phone calls require a certain type of sayer. The need **those 3** properties: 7 | 8 | * ``screen`` set to ``"phone_say"`` 9 | * ``who_style`` set to ``"phone_say_label"`` 10 | * ``what_style`` set to ``"phone_say_dialogue"`` 11 | 12 | The rest is as usual. :: 13 | 14 | define phone_eileen = Character("Eileen", screen="phone_say", who_style="phone_say_label", what_style="phone_say_dialogue") 15 | 16 | Functions 17 | --------- 18 | 19 | ``def call(caller, video=False, nosave=False)`` 20 | Starts a phone call with the ``*character*`` ``caller``. If ``video`` is true, a video call is started (this is ignored if the game is on a version prior to 7.5.0). If ``nosave`` is true, the call won't be saved to the call history. 21 | Replaces the ``narrator`` with a special narrator. 22 | The python equivalent of the ``phone call`` statement. 23 | 24 | ``def end_call()`` 25 | Ends the current phone call, and registers it for both ``*character*``\s (the caller and the current pov). 26 | Sets the ``narrator`` back and clears the video call layer. 27 | The python equivalent of the ``phone end call`` statement. 28 | 29 | ``def register_call(char1, char2, duration=None)`` 30 | Saves a call between the ``*character*``\s ``char1`` and ``char2``. If ``duration`` is not ``None``, it's a float, a number of seconds the call lasted. This is called automatically by the ``phone.calls.end_call`` function. 31 | 32 | Statements 33 | ---------- 34 | 35 | ``phone call`` 36 | Used to start a phone call. It expects a ``*character*``. If the ``video`` clause is given, a video call is started. If the ``nosave`` clause is given, the call won't be saved to the call history. 37 | 38 | ``phone end call`` 39 | Used to end a phone call. It doesn't expect anything. 40 | 41 | Example 42 | ------- 43 | :: 44 | 45 | # define two phone sayers 46 | define phone_s = Character("Sayori", screen="phone_say", who_style="phone_say_label", what_style="phone_say_dialogue") 47 | define phone_mc = Character("MC", screen="phone_say", who_style="phone_say_label", what_style="phone_say_dialogue") 48 | 49 | # create the two phone characters 50 | default pc_sayori = phone.character.Character("Sayori", phone.asset("sayori_icon.png"), "s", 21, "#22Abf8") 51 | default pc_mc = phone.character.Character("MC", phone.asset("mc_icon.png"), "mc", 35, "#484848") 52 | 53 | label phone_call_test: 54 | phone call "s" 55 | phone_s "Ohayouuu!!!!!!!!!!!!!!!!" 56 | phone_mc "Hey!" 57 | "Why is she always this energetic?" 58 | phone end call 59 | "..." 60 | 61 | return 62 | 63 | label phone_video_call_test: 64 | show sayori onlayer phone_video_call 65 | show bg sayori_room onlayer phone_video_call 66 | phone call "s" video 67 | phone_s "Hey! That's my room" 68 | phone end call 69 | "..." 70 | 71 | return -------------------------------------------------------------------------------- /docs/renpydoc.py: -------------------------------------------------------------------------------- 1 | #@PydevCodeAnalysisIgnore 2 | from __future__ import print_function 3 | from pygments.lexers.agile import PythonLexer 4 | from pygments.token import Token, Name, Operator 5 | 6 | import keywords 7 | 8 | KEYWORDS = set(keywords.keywords) 9 | PROPERTIES = set(keywords.properties) 10 | 11 | 12 | class RenPyLexer(PythonLexer): 13 | name = "Ren'Py" 14 | aliases = [ "renpy", "rpy" ] 15 | filenames = [ "*.rpy", "*.rpym" ] 16 | 17 | def get_tokens_unprocessed(self, text): 18 | for index, token, value in PythonLexer.get_tokens_unprocessed(self, text): 19 | 20 | if value.startswith("###"): 21 | continue 22 | 23 | if token == Token.Error and value == "$": 24 | yield index, Token.Keyword, value 25 | 26 | elif token in [ Name, Operator.Word ] and value in KEYWORDS: 27 | yield index, Token.Keyword, value 28 | 29 | elif token in Name and value in PROPERTIES: 30 | yield index, Name.Attribute, value 31 | 32 | else: 33 | yield index, token, value 34 | 35 | 36 | import re 37 | import sphinx.addnodes 38 | import docutils.nodes 39 | import sphinx.domains 40 | 41 | 42 | def parse_var_node(env, sig, signode): 43 | m = re.match(r'(\S+)(.*)', sig) 44 | 45 | if m.group(1).split('.')[0] in [ "config", "gui" ]: 46 | signode += docutils.nodes.Text("define ", "define" ) 47 | 48 | signode += sphinx.addnodes.desc_name(m.group(1), m.group(1)) 49 | signode += docutils.nodes.Text(m.group(2), m.group(2)) 50 | 51 | ref = m.group(1) 52 | return ref 53 | 54 | 55 | style_seen_ids = set() 56 | 57 | 58 | def parse_style_node(env, sig, signode): 59 | m = re.match(r'(\S+)(.*)', sig) 60 | 61 | name = m.group(1) 62 | desc = m.group(2) 63 | desc = " - " + desc 64 | 65 | signode += sphinx.addnodes.desc_name(name, name) 66 | signode += docutils.nodes.Text(desc, desc) 67 | 68 | ref = m.group(1) 69 | 70 | while ref in style_seen_ids: 71 | print("duplicate id:", ref) 72 | ref = ref + "_alt" 73 | 74 | style_seen_ids.add(ref) 75 | 76 | return ref 77 | 78 | 79 | class PythonIndex(sphinx.domains.Index): 80 | name = "function-class-index" 81 | localname = "Function and Class Index" 82 | shortname = "" 83 | 84 | def generate(self, docnames=None): 85 | 86 | if not isinstance(self.domain, sphinx.domains.python.PythonDomain): 87 | return [ ], False 88 | 89 | entries = [ ] 90 | 91 | for name, (docname, kind) in self.domain.data['objects'].items(): 92 | 93 | if kind == "function" or kind == "class": 94 | entries.append((name, 0, docname, name, None, None, '')) 95 | 96 | content = { } 97 | 98 | for name, subtype, docname, anchor, extra, qualifier, descr in entries: 99 | c = name[0].upper() 100 | 101 | if c not in content: 102 | content[c] = [ ] 103 | 104 | content[c].append((name, subtype, docname, anchor, extra, qualifier, descr)) 105 | 106 | for i in content.values(): 107 | i.sort() 108 | 109 | # self.domain.data['labels']["py-function-class-index"] = ("py-function-class-index", '', self.localname) 110 | 111 | return sorted(content.items()), False 112 | 113 | 114 | class CustomIndex(sphinx.domains.Index): 115 | 116 | name = "" 117 | localname = "" 118 | shortname = "" 119 | kind = "" 120 | 121 | def generate(self, docnames=None): 122 | 123 | if not isinstance(self.domain, sphinx.domains.std.StandardDomain): 124 | return [ ], False 125 | 126 | entries = [ ] 127 | 128 | for (kind, name), (docname, anchor) in self.domain.data["objects"].items(): 129 | 130 | if self.kind != kind: 131 | continue 132 | 133 | if docnames is not None and docname not in docnames: 134 | continue 135 | 136 | entries.append((name, 0, docname, anchor, None, None, '')) 137 | 138 | content = { } 139 | 140 | for name, subtype, docname, anchor, extra, qualifier, descr in entries: 141 | c = name[0].upper() 142 | 143 | if c not in content: 144 | content[c] = [ ] 145 | 146 | content[c].append((name, subtype, docname, anchor, extra, qualifier, descr)) 147 | 148 | for i in content.values(): 149 | i.sort() 150 | 151 | self.domain.data['labels'][self.kind + "-index"] = ("std-" + self.kind + "-index", '', self.localname) 152 | 153 | return sorted(content.items()), False 154 | 155 | 156 | def add_index(app, domain, object_type, title): 157 | 158 | class MyIndex(CustomIndex): 159 | name = object_type + "-index" 160 | localname = title 161 | kind = object_type 162 | 163 | app.add_index_to_domain(domain, MyIndex) 164 | # app.domains[domain].indices.append(MyIndex) 165 | 166 | 167 | def setup(app): 168 | # app.add_description_unit('property', 'propref') 169 | app.add_lexer('renpy', RenPyLexer) 170 | app.add_object_type("var", "var", "single: %s (variable)", parse_node=parse_var_node) 171 | app.add_object_type("style-property", "propref", "single: %s (style property)", parse_node=parse_style_node) 172 | app.add_object_type("transform-property", "tpref", "single: %s (transform property)") 173 | app.add_object_type("text-tag", "tt", "single: %s (text tag)") 174 | 175 | add_index(app, "std", "style-property", "Style Property Index") 176 | add_index(app, "std", "transform-property", "Transform Property Index") 177 | add_index(app, "std", "var", "Variable Index") 178 | 179 | app.add_index_to_domain('py', PythonIndex) 180 | 181 | # app.domains['py'].indices.append(PythonIndex) 182 | # app.domains['std'].data['labels']['py-function-class-index'] = ('py-function-class-index', '', 'Function and Class Index') -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx==5.0.2 2 | sphinx_nervproject_theme 3 | sphinx_markdown_tables 4 | six 5 | sphinx_rtd_theme 6 | sphinx_rtd_dark_mode 7 | jinja2==3.1.1 8 | -------------------------------------------------------------------------------- /docs/system.rst: -------------------------------------------------------------------------------- 1 | System 2 | ====== 3 | 4 | *The following functions and variables are defined in the* **phone.system** *namespace.* 5 | 6 | ``def get_battery_level()`` 7 | Returns the battery level. If the variable ``battery_level`` is ``None``, the value is taken from the player's device. 8 | 9 | ``def get_internet_connection_state()`` 10 | Returns the state of the internet connection, represented by the following constants: 11 | 12 | * ``CONNECTED`` wifi is on and connected to the internet 13 | * ``NO_INTERNET`` wifi is on but no internet connection 14 | * ``NOT_CONNECTED`` wifi is off 15 | * ``AIRPLANE_MODE`` airplane mode is on 16 | * ``CELLULAR_DATA`` wifi is off and cellular data is on 17 | 18 | ``def get_date()`` 19 | Returns the date. If the variable ``date`` is ``None``, the date used is ``datetime.datetime.now()``. 20 | 21 | ``date = None`` 22 | If not ``None``, a ``datetime.datetime`` object. 23 | 24 | ``battery_level = None`` 25 | If not ``None``, an integer. 26 | 27 | ``wifi = None`` 28 | If not ``None``, a boolean. 29 | 30 | ``locked = False`` 31 | If true, some ``Action``\s (notably in the status bar screen) won't do anything, preventing the player from changing variables when they're not supposed to. 32 | 33 | ``at_list = []`` 34 | A transform or list of transforms applied to the phone screen (overlay screens excluded). Set back to ``[]`` when exiting the phone. 35 | 36 | ``cellular_data = False`` 37 | Is cellular data on? 38 | 39 | ``airplane_mode = False`` 40 | Is airplane mode on? 41 | 42 | ``bluetooth = False`` 43 | Is bluetooth on? 44 | 45 | ``internet_connection = True`` 46 | This can be turned on/off for more a realistic gameplay (say the main character is in a very rural place, they won't have access to the internet). 47 | 48 | Other variables (``flashlight``, ``rotation_locked``, ``dark_mode``) currently don't have any use and should not be used by creators. -------------------------------------------------------------------------------- /phone/01main.rpy: -------------------------------------------------------------------------------- 1 | python early in phone: 2 | from renpy import store 3 | from store import config as renpy_config # phone.config is a substore 4 | 5 | __version__ = (3, 2, 2) 6 | __author__ = "Elckarow#8399" # smh my head my head 7 | 8 | init -150 python in phone: 9 | class _Data(object): 10 | def __call__(self): 11 | return {k: f() for k, f in config.data.items()} 12 | 13 | renpy.music.register_channel("phone_audio_message", mixer="phone", loop=False) 14 | renpy.music.register_channel("phone_music", mixer="phone", loop=True) 15 | 16 | def set_current_screen(_screen_name): 17 | global _current_screen; _current_screen = _screen_name 18 | 19 | def get_current_screen(): 20 | global _current_screen; return _current_screen 21 | 22 | import datetime 23 | def format_date(month, day, year): 24 | date = datetime.date(month=month, day=day, year=year) 25 | return date.strftime(__(config.date_format)) 26 | 27 | import time 28 | def format_time(hour, minute): 29 | return time.strftime(__(config.time_format), time.gmtime(hour * 3600 + minute * 60)) 30 | 31 | transform -150 _fits(size): 32 | subpixel True xysize (size, size) fit "contain" 33 | 34 | transform -150 _xfits(size): 35 | subpixel True xsize size fit "contain" 36 | 37 | transform -150 _yfits(size): 38 | subpixel True ysize size fit "contain" 39 | 40 | # The dictionnary containing all of the data used by the phone. 41 | default -150 phone.data = collections.defaultdict( 42 | phone._Data() 43 | ) 44 | 45 | default -100 phone.menu = False 46 | 47 | init -100 python in phone: 48 | from store import Action, Return, With 49 | 50 | NoValue = renpy.object.Sentinel("_phone_NoValue") 51 | 52 | class PhoneMenu(Action): 53 | def __init__(self, screen, *args, **kwargs): 54 | self.screen = screen 55 | self.args = args 56 | self.kwargs = kwargs 57 | 58 | def predict(self): 59 | if renpy.has_screen(self.screen): 60 | renpy.predict_screen(self.screen, *self.args, **self.kwargs) 61 | 62 | def __call__(self): 63 | call_screen(self.screen, *self.args, **self.kwargs) 64 | 65 | def get_selected(self): 66 | return renpy.get_screen(self.screen) is not None 67 | 68 | store.PhoneMenu = PhoneMenu 69 | 70 | def call_screen(_screen_name, *args, **kwargs): 71 | if not renpy.has_screen(_screen_name): 72 | raise Exception("%r is not a screen." % _screen_name) 73 | 74 | global menu 75 | menu = True 76 | 77 | first_call = renpy.context_nesting_level() == 0 78 | 79 | needs_rollback = first_call and renpy.game.context().interacting 80 | 81 | if needs_rollback: 82 | renpy.checkpoint() 83 | 84 | renpy.transition(kwargs.pop("_transition", config.enter_transition if first_call else config.intra_transition)) 85 | store._window_hide(None, True) 86 | 87 | current_screen = get_current_screen() 88 | set_current_screen(_screen_name) 89 | 90 | show_layer_at(_screen_name) 91 | rv = renpy.invoke_in_new_context(renpy.call_screen, _screen_name, *args, **kwargs) 92 | show_layer_at(current_screen or []) 93 | 94 | set_current_screen(current_screen) 95 | 96 | menu = not first_call 97 | 98 | if needs_rollback: 99 | renpy.rollback(force=True, greedy=False) 100 | 101 | return rv 102 | 103 | def PhoneReturn(value=None, transition=NoValue): 104 | return (Return(value), With(transition if transition is not NoValue else (config.exit_transition if renpy.context_nesting_level() == 1 else config.intra_transition))) 105 | 106 | store.PhoneReturn = PhoneReturn 107 | 108 | def show_layer_at(at_list, layer="master", camera=True, reset=False): 109 | if isinstance(at_list, basestring): 110 | at_list = config.layer_at_transforms.get(at_list, config.layer_at_transforms[None]) 111 | 112 | if not isinstance(at_list, list): 113 | at_list = [at_list] 114 | 115 | renpy.show_layer_at(at_list=at_list, layer=layer, camera=camera, reset=reset) 116 | 117 | def short_name(s, length): 118 | s = renpy.substitute(s) 119 | if len(s) > length: 120 | s = s[:length - 3] + "..." 121 | 122 | return s 123 | 124 | import os 125 | @renpy.pure 126 | def path_join(*paths): 127 | rv = os.path.join(*paths) 128 | if renpy.windows: 129 | rv = rv.replace("\\", "/") 130 | return rv 131 | 132 | @renpy.pure 133 | def asset(path): 134 | return path_join(config.basedir, path) 135 | 136 | def execute_default(f, id): 137 | def run(load): 138 | if id not in _defaults_ran: 139 | _defaults_ran.add(id) 140 | f() 141 | if load: renpy.block_rollback() 142 | 143 | renpy_config.start_callbacks.append(renpy.partial(run, load=False)) 144 | renpy_config.after_load_callbacks.append(renpy.partial(run, load=True)) 145 | 146 | # a set() object 147 | # renamed it because why not 148 | default -999 phone._defaults_ran = phone._id_ran_on_start 149 | 150 | default -100 phone._current_screen = None 151 | 152 | # The base screen for all phone screens. 153 | screen _phone(xpos=0.5, xanchor=0.5, ypos=0.1, yanchor=0.1, horizontal=False): 154 | frame style "empty" modal True: 155 | at transform: 156 | subpixel True zoom gui.phone_zoom * (1.3 if horizontal else 1.0) 157 | xpos xpos xanchor xanchor 158 | ypos ypos yanchor yanchor 159 | 160 | background Transform( 161 | phone.asset("background.png"), 162 | subpixel=True, 163 | align=(0.5, 0.5), 164 | rotate=-90 * horizontal, 165 | transform_anchor=horizontal 166 | ) 167 | 168 | if not horizontal: 169 | padding gui.phone_margin 170 | xysize (gui.phone_xsize, gui.phone_ysize) 171 | else: 172 | padding (gui.phone_margin[1], gui.phone_margin[0], gui.phone_margin[2], gui.phone_margin[3]) 173 | xysize (gui.phone_ysize, gui.phone_xsize) 174 | 175 | fixed style "empty": 176 | at transform: 177 | crop (0.0, 0.0, 1.0, 1.0) crop_relative True 178 | 179 | fixed style "empty": 180 | if phone.system.at_list: # https://github.com/renpy/renpy/issues/4628 181 | at phone.system.at_list 182 | 183 | add "#fff" 184 | transclude 185 | 186 | fixed style "empty": 187 | for o in phone.config.overlay_screens: 188 | use expression o 189 | 190 | # https://www.renpy.org/doc/html/incompatible.html#incompatible-7-5-2 191 | # the thing just above 192 | # about config.at_transform_compare_full_context 193 | $ alpha = 1.0 - phone.system.brightness 194 | add "#000": 195 | at transform: 196 | alpha alpha 197 | 198 | on "hide" action ( 199 | SetVariable("phone.system.at_list", []), 200 | ) 201 | 202 | init 1500: 203 | # narrator is guarenteed to exist at init 1400 204 | # see renpy/common/00definitions.rpy 205 | define _phone_narrator = Character(kind=narrator, screen="phone_say", what_style="phone_say_dialogue") 206 | define _backup_narrator = narrator 207 | 208 | python in phone: 209 | if store.PhoneMenu is not PhoneMenu: 210 | raise Exception("store.PhoneMenu is a reserved name. (value is %r)" % store.PhoneMenu) 211 | store.PhoneMenu = PhoneMenu 212 | 213 | if store.PhoneReturn is not PhoneReturn: 214 | raise Exception("store.PhoneReturn is a reserved name. (value is %r)" % store.PhoneReturn) 215 | store.PhoneReturn = PhoneReturn 216 | 217 | if store.is_renpy_version_or_above(7, 6, 0): 218 | renpy_config.detached_layers.append(config.video_call_layer) 219 | 220 | # https://github.com/renpy/renpy/issues/5044 221 | renpy_config.layer_clipping[config.video_call_layer] = (0, 0, renpy_config.screen_width, renpy_config.screen_height) 222 | 223 | # previous name, when the function it's used in was undocumented 224 | default -1000 phone._id_ran_on_start = set() -------------------------------------------------------------------------------- /phone/apps/app_base.rpy: -------------------------------------------------------------------------------- 1 | screen app_base(action=NullAction()): 2 | style_prefix "app_base" 3 | 4 | frame: 5 | ysize 50 + (gui.phone_status_bar_height * bool(phone.config.status_bar)) 6 | top_padding 10 + (gui.phone_status_bar_height * bool(phone.config.status_bar)) 7 | textbutton _("< Back"): 8 | action (action, PhoneReturn()) 9 | sensitive phone.menu 10 | 11 | transclude 12 | 13 | style app_base_frame is empty: 14 | background "#F2F2F2" 15 | xfill True 16 | xpadding 10 17 | bottom_padding 10 18 | 19 | style app_base_hbox is empty: 20 | spacing 5 21 | align (0.5, 0.5) 22 | 23 | style app_base_text is empty: 24 | outlines [ ] 25 | yalign 0.5 26 | color "#000" size 19 27 | font phone.asset("Aller_Rg.ttf") 28 | 29 | style app_base_button is empty: 30 | yalign 0.5 31 | xalign 0.0 32 | 33 | style app_base_button_text is app_base_text: 34 | color "#0094FF" 35 | size 18 -------------------------------------------------------------------------------- /phone/apps/calendar/calendar.rpy: -------------------------------------------------------------------------------- 1 | init -100 python in phone.calendar: 2 | from renpy import store 3 | from store import _, At, _fits, phone 4 | from store.phone import system, config 5 | import calendar 6 | 7 | MONDAY = calendar.MONDAY 8 | TUESDAY = calendar.TUESDAY 9 | WEDNESDAY = calendar.WEDNESDAY 10 | THURSDAY = calendar.THURSDAY 11 | FRIDAY = calendar.FRIDAY 12 | SATURDAY = calendar.SATURDAY 13 | SUNDAY = calendar.SUNDAY 14 | 15 | renpy.const("phone.calendar.MONDAY") 16 | renpy.const("phone.calendar.TUESDAY") 17 | renpy.const("phone.calendar.WEDNESDAY") 18 | renpy.const("phone.calendar.THURSDAY") 19 | renpy.const("phone.calendar.FRIDAY") 20 | renpy.const("phone.calendar.SATURDAY") 21 | renpy.const("phone.calendar.SUNDAY") 22 | 23 | days = ( 24 | _("Monday"), 25 | _("Tuesday"), 26 | _("Wednesday"), 27 | _("Thursday"), 28 | _("Friday"), 29 | _("Saturday"), 30 | _("Sunday") 31 | ) 32 | 33 | renpy.const("phone.calendar.days") 34 | 35 | months = ( 36 | "", 37 | _("January"), 38 | _("February"), 39 | _("March"), 40 | _("April"), 41 | _("May"), 42 | _("June"), 43 | _("July"), 44 | _("August"), 45 | _("September"), 46 | _("October"), 47 | _("November"), 48 | _("December") 49 | ) 50 | 51 | renpy.const("phone.calendar.months") 52 | 53 | class _CalendarEntry(object): 54 | def __init__(self, day): 55 | self.day = day 56 | self.description = None 57 | 58 | class Calendar(calendar.Calendar): 59 | def __init__(self, month, year=2017, first_day=SUNDAY): 60 | super(Calendar, self).__init__(first_day) 61 | 62 | self.month = month 63 | self.month_name = months[month] 64 | self.year = year 65 | 66 | self.__days = [ ] 67 | self.start_offset = self.end_offset = 0 68 | 69 | end = False 70 | for d in self.itermonthdays(year, month): 71 | if d == 0: 72 | self.__days.append(None) 73 | if not end: 74 | self.start_offset += 1 75 | else: 76 | self.end_offset += 1 77 | else: 78 | self.__days.append(_CalendarEntry(d)) 79 | end = True 80 | 81 | def is_day_passed(self, day): 82 | if not 0 < day <= self.lenght(): return False 83 | date = system.get_date() 84 | return (self.year, self.month, day) < (date.year, date.month, date.day) 85 | 86 | def lenght(self, offsets=False): 87 | if offsets: return len(self.__days) 88 | return self.lenght(True) - self.end_offset - self.start_offset 89 | 90 | def get_week_days(self): 91 | return get_week_days(self.firstweekday) 92 | 93 | @property 94 | def rows(self): 95 | return self.lenght(True) // 7 96 | 97 | def __getitem__(self, i): 98 | return self.__days[self.start_offset:self.lenght(True) - self.end_offset][i - 1] 99 | 100 | def __iter__(self): 101 | return iter(self.__days) 102 | 103 | def get_week_days(first_day=SUNDAY): 104 | for i in range(first_day, 7): 105 | yield days[i] 106 | 107 | for i in range(0, first_day): 108 | yield days[i] 109 | 110 | def day_name(year, month, day): 111 | return days[calendar.weekday(year, month, day)] 112 | 113 | def add_calendar(year, month, key=None, first_day=SUNDAY): 114 | if renpy.is_init_phase(): 115 | phone.execute_default(renpy.partial(add_calendar, year=year, month=month, key=key, first_day=first_day), ("_phone_add_calendar", month, year, key)) 116 | else: 117 | key = character.character(key).key 118 | 119 | if get_calendar(year=year, month=month, key=key) is not None: 120 | raise Exception("a calendar for the year {} and month {} already exists for the *character* {}" \ 121 | .format(year, month, key)) 122 | 123 | calendars = store.phone.data[key]["calendars"] 124 | calendars.append(Calendar(year=year, month=month, first_day=first_day)) 125 | 126 | calendars.sort(key=lambda c: (c.year, c.month)) 127 | 128 | def add_calendar_to_all_characters(year, month, first_day=SUNDAY): 129 | if renpy.is_init_phase(): 130 | phone.execute_default(renpy.partial(add_calendar_to_all_characters, year=year, month=month, first_day=first_day), ("_phone_add_calendar", month, year)) 131 | else: 132 | for key in character._characters: 133 | add_calendar(year=year, month=month, first_day=first_day, key=key) 134 | 135 | _calendar_button_background = At(config.basedir + "circle.png", store._fits(None)) 136 | 137 | def get_calendar(year, month, key=None): 138 | key = character.character(key).key 139 | for calendar in data[key]["calendars"]: 140 | if calendar.year == year and calendar.month == month: 141 | return calendar 142 | return None 143 | 144 | def _calendar_default_index(m): 145 | n = config.default_calendar_index 146 | 147 | if n is True: 148 | pov_key = store.pov_key 149 | date = system.get_date() 150 | 151 | c = get_calendar(year=date.year, month=date.month, key=pov_key) 152 | 153 | if c is None: 154 | raise Exception("no calendar with the year {} and month {} exists for the *character* {}".format(year, month, pov_key)) 155 | 156 | n = phone.data[pov_key]["calendars"].index(c) 157 | 158 | elif n < 0: 159 | n = m + n 160 | 161 | return n 162 | 163 | screen phone_calendars(): 164 | default calendars = phone.data[pov_key]["calendars"] 165 | default m = len(calendars) - 1 166 | default n = phone.calendar._calendar_default_index(m + 1) 167 | default selected_entry = None 168 | default yadj = ui.adjustment() 169 | 170 | $ calendar = calendars[n] 171 | 172 | use _phone(): 173 | style_prefix "phone_calendar" 174 | 175 | side "t c": 176 | use app_base(): 177 | style_prefix "app_base" 178 | text _("Calendar") xalign 0.5 text_align 0.5 179 | 180 | grid 7 calendar.rows + 1 at Flatten xalign 0.5: 181 | for day in calendar.get_week_days(): 182 | text __(day)[0] style "phone_calendar_days_text" 183 | 184 | for entry in calendar: 185 | if entry is None: 186 | null width gui.phone_calendar_button_size 187 | else: 188 | button: 189 | at transform: 190 | subpixel True yoffset -15 191 | on idle: 192 | matrixcolor BrightnessMatrix(0.0) 193 | on hover, selected_idle: 194 | matrixcolor BrightnessMatrix(-0.1) 195 | on selected_hover: 196 | matrixcolor BrightnessMatrix(-0.2) 197 | 198 | if calendar.is_day_passed(entry.day): 199 | background Transform(phone.calendar._calendar_button_background, matrixcolor=TintMatrix("#9e9e9e")) 200 | else: 201 | hover_background Transform(phone.calendar._calendar_button_background, matrixcolor=TintMatrix("#e0e0e0")) 202 | selected_background Transform(phone.calendar._calendar_button_background, matrixcolor=TintMatrix("#e0e0e0")) 203 | 204 | action ( 205 | If( 206 | selected_entry is not entry, 207 | SetScreenVariable("selected_entry", entry), 208 | SetScreenVariable("selected_entry", None) 209 | ), 210 | Function(yadj.change, 0), 211 | SelectedIf(selected_entry is entry) 212 | ) 213 | 214 | text str(entry.day) style "phone_calendar_button_text" 215 | 216 | if entry.description is not None: 217 | frame style "empty" align (1.0, 0.0) xysize (16, 16): 218 | background Transform(phone.calendar._calendar_button_background, matrixcolor=TintMatrix("#8f8f8fff")) 219 | text "?" style "phone_calendar_button_text_special": 220 | at transform: 221 | subpixel True 222 | 223 | vbox style_prefix "phone_calendar_notes" yalign 1.0: 224 | spacing 5 225 | 226 | side "l c r" xalign 0.5: 227 | textbutton "<" action If(n != 0, (SetScreenVariable("n", n - 1), SetScreenVariable("selected_entry", None))) 228 | text _("[calendar.month_name!t]-[calendar.year]") size 25 xalign 0.5 text_align 0.5 229 | textbutton ">" action If(n != m, (SetScreenVariable("n", n + 1), SetScreenVariable("selected_entry", None))) 230 | 231 | frame at CurriedRoundedCorners(radius=(0, 25, 0, 25)): 232 | vbox spacing 3 at Flatten: 233 | text _("Notes:") size 22 234 | 235 | viewport: 236 | draggable True mousewheel True 237 | yadjustment yadj 238 | 239 | if selected_entry is not None: 240 | if selected_entry.description is not None: 241 | text selected_entry.description 242 | else: 243 | text _("No description provided.") 244 | 245 | style phone_calendar_side is empty: 246 | yfill True xfill True 247 | 248 | style phone_calendar_grid is empty: 249 | spacing 10 250 | 251 | style phone_calendar_button is empty: 252 | xysize (gui.phone_calendar_button_size, gui.phone_calendar_button_size) 253 | 254 | style phone_calendar_button_text is empty: 255 | color "#000" 256 | outlines [] 257 | size 16 258 | align (0.5, 0.5) text_align 0.5 259 | font phone.asset("Aller_Rg.ttf") 260 | 261 | style phone_calendar_button_text_special is phone_calendar_button_text: 262 | size 12 263 | 264 | style phone_calendar_days_text is phone_calendar_button_text: 265 | size 17 266 | 267 | style phone_calendar_notes_side is empty: 268 | xsize 0.9 xfill True 269 | 270 | style phone_calendar_notes_text is empty: 271 | font "DejaVuSans.ttf" 272 | color "#000" outlines [] 273 | size 18 274 | 275 | style phone_calendar_notes_button is empty: 276 | yalign 0.5 277 | style phone_calendar_notes_button_text is phone_calendar_notes_text: 278 | size 21 279 | 280 | style phone_calendar_notes_frame is empty: 281 | background "#e0e0e0" 282 | padding (13, 7, 13, 0) 283 | xfill True ysize 180 284 | 285 | style phone_calendar_notes_vbox is empty: 286 | xfill True 287 | 288 | init -50 python in phone.calendar: 289 | from store.phone import character 290 | 291 | init python in phone: 292 | renpy_config.start_callbacks.append(lambda: setattr(calendar, "data", data)) -------------------------------------------------------------------------------- /phone/apps/call_history/call_history.rpy: -------------------------------------------------------------------------------- 1 | screen phone_call_history(): 2 | default call_history = phone.data[pov_key]["call_history"] 3 | 4 | use _phone(): 5 | style_prefix "phone_call_history" 6 | 7 | side "t c": 8 | use app_base(): 9 | style_prefix "app_base" 10 | text _("Calls") xalign 0.5 text_align 0.5 11 | 12 | if not call_history: 13 | text _("No recent calls") style "phone_call_history_empty" align (0.5, 0.05) 14 | 15 | else: 16 | viewport: 17 | draggable True 18 | mousewheel True 19 | yfill True 20 | 21 | frame: 22 | vbox: 23 | for i, entry in enumerate(call_history): 24 | $ char = phone.character.character(entry.caller) 25 | 26 | if i != 0: 27 | add Solid("#000"): 28 | xysize (1.0, 1) nearest True 29 | 30 | button: 31 | action NullAction() 32 | 33 | hbox: 34 | add char.icon at _fits(46) yalign 0.5 35 | 36 | fixed: 37 | hbox style "empty" yalign 0.2 spacing 10: 38 | text phone.short_name(char.name, 26) 39 | if entry.duration is not None: 40 | text "-" 41 | text entry._duration_to_str() 42 | 43 | text __("The {date} at {time}").format( 44 | date=phone.format_date(entry.date.month, entry.date.day, entry.date.year), 45 | time=phone.format_time(entry.date.hour, entry.date.minute) 46 | ): 47 | style "phone_call_history_date_text" yalign 1.0 48 | 49 | style phone_call_history_side is phone_contacts_side 50 | style phone_call_history_frame is phone_contacts_frame 51 | style phone_call_history_vbox is phone_contacts_vbox 52 | style phone_call_history_button is phone_contacts_button 53 | style phone_call_history_fixed is empty 54 | style phone_call_history_hbox is phone_contacts_hbox 55 | style phone_call_history_text is phone_contacts_text: 56 | color "#000" 57 | 58 | style phone_call_history_empty is phone_contacts_no_friends 59 | style phone_call_history_date_text is phone_contacts_date_text -------------------------------------------------------------------------------- /phone/apps/calls/call_functions.rpy: -------------------------------------------------------------------------------- 1 | init -100 python in phone.calls: 2 | from renpy import store 3 | from store import Transform, BrightnessMatrix, phone 4 | from store.phone import character, config, show_layer_at, set_current_screen, system 5 | import time 6 | 7 | config.layer_at_transforms["phone_call"] = Transform(matrixcolor=BrightnessMatrix(-0.21), blur=20) 8 | config.hide_status_bar_screens.append("phone_call") 9 | 10 | def call(caller, video=False, nosave=False): 11 | store._window_hide() 12 | 13 | global _current_caller 14 | if _current_caller is not None: 15 | raise Exception("can't have 2 phone calls at the same time") 16 | _current_caller = character.character(caller) 17 | store.narrator = store._phone_narrator 18 | 19 | set_current_screen("phone_call") 20 | show_layer_at("phone_call") 21 | 22 | renpy.show_screen("phone_call", video=video) 23 | renpy.with_statement(config.enter_transition) 24 | 25 | global _nosave 26 | _nosave = bool(nosave) 27 | 28 | def end_call(): 29 | global _current_caller 30 | if _current_caller is None: 31 | raise Exception("ending phone call, but no call was ever made") 32 | 33 | global _call_time_st 34 | register_call(character.character(store.pov_key), _current_caller, _call_time_st) 35 | _current_caller = None 36 | store.narrator = store._backup_narrator 37 | _call_time_st = 0.0 38 | 39 | set_current_screen(None) 40 | 41 | show_layer_at([], reset=True) 42 | renpy.hide_screen("phone_call") 43 | if store.is_renpy_version_or_above(7, 5, 0): 44 | renpy.scene(config.video_call_layer) 45 | renpy.with_statement(config.exit_transition) 46 | 47 | set_current_screen(None) 48 | store._window_auto = True 49 | 50 | class _CallEntry(object): 51 | def __init__(self, caller, date, duration): 52 | self.caller = character.character(caller).key 53 | self.date = date 54 | self.duration = duration 55 | 56 | def _duration_to_str(self): 57 | if self.duration is None: return "" 58 | return time.strftime("%M:%S", time.gmtime(self.duration)) 59 | 60 | def register_call(char1, char2, duration=None): 61 | key1 = character.character(char1).key 62 | key2 = character.character(char2).key 63 | 64 | date = system.get_date() 65 | 66 | global _nosave 67 | if _nosave is not None and not _nosave: 68 | _nosave = None 69 | 70 | ch1 = phone.data[key1]["call_history"] 71 | ch1.append(_CallEntry(key2, date, duration)) 72 | 73 | while len(ch1) > config.call_history_length: ch1.pop(0) 74 | 75 | ch2 = phone.data[key2]["call_history"] 76 | ch2.append(_CallEntry(key1, date, duration)) 77 | 78 | while len(ch2) > config.call_history_length: ch2.pop(0) 79 | 80 | default -100 phone.calls._current_caller = None 81 | default -100 phone.calls._nosave = None -------------------------------------------------------------------------------- /phone/apps/calls/call_screen.rpy: -------------------------------------------------------------------------------- 1 | init -100 python in phone.calls: 2 | from store import Text 3 | def _call_time(st, at): 4 | global _call_time_st; _call_time_st = st # breh. st might not be the same when loading 5 | return Text(time.strftime("%M:%S", time.gmtime(st)), style="phone_call_time"), 0.0 6 | 7 | default phone.calls._call_time_st = 0.0 8 | 9 | screen phone_call(video=False): 10 | use _phone(xpos=gui.phone_call_xpos, xanchor=0.0): 11 | add Solid("#302D29") 12 | 13 | # https://github.com/Elckarow/Better-EMR-Phone/issues/14 14 | # and https://github.com/Elckarow/Better-EMR-Phone/commit/b8580f4918ab011c3789058401f57daeda65e8f0 15 | if phone.calls._current_caller is not None: 16 | if video and is_renpy_version_or_above(7, 6, 0): # _phone_video_call uses the `Layer` displayable 17 | use _phone_video_call() 18 | else: 19 | use _phone_call() 20 | 21 | if not phone.config.quick_menu and quick_menu: 22 | use quick_menu() 23 | 24 | screen _phone_call(): 25 | style_prefix "phone_call" 26 | 27 | vbox: 28 | text phone.short_name(phone.calls._current_caller.name, 12) 29 | add DynamicDisplayable(phone.calls._call_time) 30 | 31 | frame: 32 | add phone.calls._current_caller.icon at _fits(None) 33 | 34 | if phone.config.quick_menu and quick_menu: 35 | frame style "empty" xalign 0.5 ypos 0.45: 36 | use phone_quick_menu() 37 | 38 | add phone.asset("hang_up.png"): 39 | subpixel True xysize (63, 63) 40 | xalign 0.5 ypos 0.8 41 | 42 | style phone_call_vbox is empty: 43 | spacing 3 44 | ypos 0.05 45 | xfill True 46 | 47 | style phone_call_text is empty: 48 | xalign 0.5 49 | text_align 0.5 50 | outlines [ ] 51 | line_spacing 0 52 | size 24 53 | font phone.asset("Aller_Rg.ttf") 54 | hyperlink_functions hyperlink_functions_style("phone_call_text_hyperlink") 55 | 56 | style phone_call_text_hyperlink is phone_call_text: 57 | hover_underline True 58 | 59 | style phone_call_time is phone_call_text: 60 | size 16 61 | 62 | style phone_call_frame is empty: 63 | background CircleDisplayable(2) 64 | xysize ( 120, 120) # :) 65 | padding (int(22 * (120 / 404)), int(22 * (120 / 404))) 66 | ypos 0.18 67 | xalign 0.5 68 | 69 | screen _phone_video_call(): 70 | style_prefix "phone_video_call" 71 | 72 | add Layer(phone.config.video_call_layer): 73 | at Transform(**phone.config.video_call_layer_transform_properties) 74 | 75 | vbox: 76 | text _("Facetime - [phone.calls._current_caller.name!ti]") 77 | add DynamicDisplayable(phone.calls._call_time) 78 | 79 | use phone_quick_menu_video() 80 | 81 | style phone_video_call_vbox is phone_call_vbox: 82 | ypos 0.03 83 | 84 | style phone_video_call_text is phone_call_text: 85 | size 27 -------------------------------------------------------------------------------- /phone/apps/calls/quick_menu.rpy: -------------------------------------------------------------------------------- 1 | screen phone_quick_menu(): 2 | grid 3 2 style_prefix "phone_quick_menu": 3 | vbox: 4 | imagebutton: 5 | idle phone.asset("quick_menu_history_idle.png") 6 | hover phone.asset("quick_menu_history_selected.png") 7 | selected_idle phone.asset("quick_menu_history_selected.png") 8 | action ShowMenu("history") 9 | text _("History") 10 | 11 | vbox: 12 | imagebutton: 13 | idle phone.asset("quick_menu_afm_idle.png") 14 | hover phone.asset("quick_menu_afm_selected.png") 15 | selected_idle phone.asset("quick_menu_afm_selected.png") 16 | action Preference("auto-forward", "toggle") 17 | text _("Auto") 18 | 19 | vbox: 20 | imagebutton: 21 | idle phone.asset("quick_menu_skip_idle.png") 22 | hover phone.asset("quick_menu_skip_selected.png") 23 | selected_idle phone.asset("quick_menu_skip_selected.png") 24 | action Skip() 25 | text _("Skip") 26 | 27 | vbox: 28 | imagebutton: 29 | idle phone.asset("quick_menu_settings_idle.png") 30 | hover phone.asset("quick_menu_settings_selected.png") 31 | selected_idle phone.asset("quick_menu_settings_selected.png") 32 | action ShowMenu("preferences") 33 | text _("Settings") 34 | 35 | vbox: 36 | imagebutton: 37 | idle phone.asset("quick_menu_save_idle.png") 38 | hover phone.asset("quick_menu_save_selected.png") 39 | selected_idle phone.asset("quick_menu_save_selected.png") 40 | action ShowMenu("save") 41 | text _("Save") 42 | 43 | vbox: 44 | imagebutton: 45 | idle phone.asset("quick_menu_load_idle.png") 46 | hover phone.asset("quick_menu_load_selected.png") 47 | selected_idle phone.asset("quick_menu_load_selected.png") 48 | action ShowMenu("load") 49 | text _("Load") 50 | 51 | style phone_quick_menu_grid is empty: 52 | xspacing 31 yspacing 22 53 | 54 | style phone_quick_menu_vbox is empty 55 | style phone_quick_menu_text is phone_call_time: 56 | size 14 57 | 58 | screen phone_quick_menu_video(): 59 | default qm = False 60 | default anim_time = 0.35 61 | 62 | showif qm: 63 | add "#000": 64 | at transform: 65 | alpha 0.0 66 | on show: 67 | ease anim_time alpha 0.35 68 | on hide: 69 | ease anim_time alpha 0.0 70 | 71 | vbox style "empty" yalign 1.0 xsize 1.0 xfill True: 72 | button style "empty" padding (5, 7, 5, 4) xalign 0.5: 73 | at transform: 74 | ease anim_time matrixtransform RotateMatrix(0, 0, 180 * qm) matrixcolor OpacityMatrix(0.8 if qm else 0.6) 75 | 76 | action ToggleLocalVariable("qm") 77 | 78 | add phone.asset("arrow_icon.png"): 79 | at transform: 80 | subpixel True xysize (70, 18) 81 | 82 | showif qm: 83 | frame style "empty" top_padding 30 bottom_padding 15 xsize 1.0 modal True: 84 | at transform: 85 | subpixel True crop (0, 0, 1.0, 0.0) 86 | on show: 87 | ease anim_time crop (0, 0, 1.0, 1.0) alpha 1.0 88 | on hide: 89 | ease anim_time crop (0, 0, 1.0, 0.0) alpha 0.0 90 | 91 | background "#00000060" 92 | 93 | vbox style "empty" xalign 0.5: 94 | use phone_quick_menu() 95 | 96 | null height 15 97 | 98 | add phone.asset("hang_up.png"): 99 | subpixel True xysize (63, 63) xalign 0.5 -------------------------------------------------------------------------------- /phone/apps/calls/say.rpy: -------------------------------------------------------------------------------- 1 | screen phone_say(who, what): 2 | style_prefix "phone_say" 3 | 4 | hbox: 5 | null width ((config.screen_width * gui.phone_call_xpos) + (gui.phone_xsize * gui.phone_zoom)) 6 | 7 | frame: 8 | if who is not None: 9 | window style "phone_say_namebox": 10 | text who id "who" 11 | 12 | window: 13 | text what id "what" 14 | 15 | style phone_say_frame is empty: 16 | xfill True yfill True 17 | padding (12, 15) 18 | 19 | style phone_say_namebox is empty: 20 | yanchor 1.0 ypos 0.451 21 | xsize 200 xalign 0.5 22 | 23 | style phone_say_window is empty: 24 | ypos 0.471 xalign 0.5 25 | xsize 600 26 | 27 | style phone_say_dialogue is empty: 28 | xalign 0.5 29 | text_align 0.5 30 | ypos 0.0 31 | outlines [ ] 32 | color "#fff" 33 | font phone.asset("JetBrainsMono-Regular.ttf") 34 | 35 | style phone_say_label is phone_say_dialogue: 36 | font phone.asset("JetBrainsMono-ExtraBold.ttf") 37 | size 27 -------------------------------------------------------------------------------- /phone/apps/contacts/contacts.rpy: -------------------------------------------------------------------------------- 1 | screen phone_contacts(): 2 | default group_chats = phone.data[pov_key]["group_chats"] 3 | 4 | use _phone(): 5 | style_prefix "phone_contacts" 6 | 7 | side "t c": 8 | use app_base(): 9 | style_prefix "app_base" 10 | text _("Messages") xalign 0.5 text_align 0.5 11 | 12 | if not group_chats: 13 | text _("No group chats") style "phone_contacts_no_friends" align (0.5, 0.05) 14 | 15 | else: 16 | viewport: 17 | draggable True 18 | mousewheel True 19 | yfill True 20 | 21 | frame: 22 | vbox: 23 | for i, gc in enumerate(group_chats): 24 | $ group_chat = phone.group_chat.group_chat(gc) 25 | 26 | if i != 0: 27 | add Solid("#000"): 28 | xysize (1.0, 1) nearest True 29 | 30 | button: 31 | action ( 32 | SetField(phone.discussion, "_group_chat", group_chat), 33 | SetField(group_chat, "unread", False), 34 | PhoneMenu("phone_discussion") 35 | ) 36 | 37 | hbox: 38 | add group_chat.icon at _fits(46) yalign 0.5 39 | 40 | fixed: 41 | text phone.short_name(group_chat.name, 26) yalign 0.2: 42 | if group_chat.unread: 43 | color "#000" 44 | 45 | text ( 46 | _("The [group_chat._date_text] at [group_chat._hour_text]") 47 | if group_chat.number_of_messages != 0 48 | else _("Empty group chat") 49 | ): 50 | style "phone_contacts_date_text" yalign 1.0 51 | 52 | style phone_contacts_side is empty: 53 | xfill True 54 | yfill True 55 | 56 | style phone_contacts_frame is empty: 57 | padding (10, 0, 10, 0) 58 | 59 | style phone_contacts_vbox is empty: 60 | xfill True 61 | spacing 0 62 | 63 | style phone_contacts_button is empty: 64 | xfill True 65 | hover_background Solid("#e4e4e4") 66 | ysize 60 67 | padding (10, 7) 68 | 69 | style phone_contacts_hbox is empty: 70 | spacing 6 71 | 72 | style phone_contacts_text is empty: 73 | outlines [ ] 74 | color "#525252" 75 | size 18 76 | font phone.asset("Aller_Rg.ttf") 77 | 78 | style phone_contacts_no_friends is phone_contacts_text: 79 | color "#000" 80 | size 20 81 | 82 | style phone_contacts_date_text is phone_contacts_text: 83 | color "#9d9d9d" 84 | size 14 -------------------------------------------------------------------------------- /phone/apps/discussion/audio_messages.rpy: -------------------------------------------------------------------------------- 1 | init -100 python in phone.discussion.audio_messages: 2 | from renpy import store 3 | from store import get_pos, TintMatrix, Flatten 4 | from store.phone import config 5 | 6 | current_p = None 7 | 8 | def reset(): 9 | global current_p 10 | current_p = None 11 | renpy.music.stop("phone_audio_message") 12 | renpy.music.set_pause(False, "phone_audio_message") 13 | 14 | def play_audio(p, audio): 15 | global current_p 16 | if current_p is p: 17 | if renpy.music.is_playing("phone_audio_message"): 18 | renpy.music.set_pause(not renpy.music.get_pause("phone_audio_message"), "phone_audio_message") 19 | else: 20 | renpy.music.play(audio, "phone_audio_message", loop=False) 21 | else: 22 | renpy.music.play(audio, "phone_audio_message", loop=False) 23 | current_p = p 24 | 25 | def button_image(st, at, p): 26 | global current_p 27 | if ( 28 | current_p is p 29 | and renpy.music.is_playing("phone_audio_message") 30 | and not renpy.music.get_pause("phone_audio_message") 31 | ): 32 | image = config.basedir + "pause_icon.png" 33 | 34 | else: 35 | image = config.basedir + "play_icon.png" 36 | 37 | return image, 0.0 38 | 39 | wave_color = TintMatrix("#727272")(None, 1.0) 40 | 41 | class AudioWave(object): 42 | def __init__(self, p): 43 | self.p = p 44 | 45 | def __call__(self, child): 46 | return Flatten(_AudioWaveDisplayable(child, self.p)) 47 | 48 | class _AudioWaveDisplayable(renpy.Displayable): 49 | def __init__(self, d, p): 50 | super(_AudioWaveDisplayable, self).__init__() 51 | 52 | self.d = renpy.displayable(d) 53 | self.p = p 54 | 55 | def render(self, w, h, st, at): 56 | renpy.redraw(self, 0.0) 57 | 58 | cr = renpy.render(self.d, w, h, st, at) 59 | 60 | global current_p 61 | if current_p is not self.p: return cr 62 | 63 | d = renpy.music.get_duration("phone_audio_message") 64 | if not d: return cr 65 | 66 | pos = get_pos("phone_audio_message") 67 | width, height = cr.get_size() 68 | 69 | mr = cr.subsurface((0, 0, min(((pos / d) * width), width), height)) 70 | mr.add_shader("renpy.matrixcolor") 71 | mr.add_uniform("u_renpy_matrixcolor", wave_color) 72 | 73 | rv = renpy.Render(width, height) 74 | rv.blit(cr, (0, 0)) 75 | rv.blit(mr, (0, 0), main=False) 76 | return rv 77 | 78 | def visit(self): 79 | return [self.d] -------------------------------------------------------------------------------- /phone/apps/discussion/discussion.rpy: -------------------------------------------------------------------------------- 1 | init -100 python in phone.discussion: 2 | from renpy.store import store, ui, pause, phone 3 | from store.phone import config, show_layer_at, set_current_screen, format_date, format_time, emojis 4 | import datetime 5 | 6 | def sort_messages(key): 7 | phone.data[character(key).key]["group_chats"].sort(key=lambda gc: group_chat(gc).date, reverse=True) 8 | 9 | def _check_for_tags(s): 10 | if renpy.filter_text_tags(s, allow=config.message_text_tags) != s: 11 | raise ValueError("only the following text tags are allowed:\n{}\n\ntext: '{}'".format("\n".join(config.message_text_tags), s)) 12 | 13 | def set_up_group_chat(gc): 14 | global _group_chat 15 | 16 | if gc is None: 17 | if _group_chat is not None: 18 | return 19 | else: 20 | raise Exception("group chat not given (no previous group chat was found)") 21 | 22 | gc = group_chat(gc) 23 | 24 | if not gc._characters: 25 | raise Exception("group chat '{}' has no characters".format(gc.name)) 26 | 27 | _group_chat = gc 28 | _group_chat.unread = False 29 | 30 | _yadjustment.value = float("inf") 31 | 32 | def discussion(gc): 33 | set_up_group_chat(gc) 34 | 35 | store._window_hide() 36 | 37 | set_current_screen("phone_discussion") 38 | show_layer_at("phone_discussion") 39 | renpy.show_screen("phone_discussion") 40 | renpy.with_statement(config.enter_transition) 41 | 42 | store._window_auto = True 43 | 44 | def end_discussion(): 45 | global _group_chat 46 | if _group_chat is None: return 47 | 48 | store._window_hide() 49 | 50 | for key in _group_chat._characters: 51 | sort_messages(key) 52 | 53 | if _group_chat.transient: 54 | _group_chat.clear() 55 | 56 | _group_chat = None 57 | 58 | show_layer_at([], reset=True) 59 | renpy.hide_screen("phone_discussion") 60 | renpy.with_statement(config.exit_transition) 61 | 62 | set_current_screen(None) 63 | 64 | store._window_auto = True 65 | 66 | class _Payload(object): 67 | def __init__(self, source, data, _type): 68 | self.source = source 69 | self.data = data 70 | if _type not in _PayloadTypes.ALL: raise Exception("'{}' is not a valid payload type".format(_type)) 71 | self.type = _type 72 | 73 | def remove_text_tags(s): 74 | s = emojis.format_emoji_tag(s) 75 | return renpy.filter_text_tags(s, allow=()) 76 | 77 | def _run_callbacks(gc, event, payload): 78 | callback_object = object() 79 | 80 | callback_object.source = payload.source 81 | callback_object.type = payload.type 82 | 83 | if payload.type == VIDEO: 84 | callback_object.data = None 85 | else: 86 | callback_object.data = payload.data 87 | 88 | for i in config.discussion_callbacks: 89 | i(gc, event, callback_object) 90 | 91 | def _discussion_coroutine(): 92 | store._window_hide() 93 | 94 | global _current_payload 95 | _current_payload = payload = yield 96 | 97 | if _group_chat._page == 0: 98 | _yadjustment.value = float("inf") 99 | 100 | _run_callbacks(_group_chat, "start", payload) 101 | 102 | _dismiss_pause = store._dismiss_pause 103 | store._dismiss_pause = True 104 | p = yield 105 | pause(p) 106 | store._dismiss_pause = _dismiss_pause 107 | 108 | _run_callbacks(_group_chat, "end", payload) 109 | 110 | if _group_chat._page == 0: 111 | _yadjustment.value = float("inf") 112 | 113 | _current_payload = None 114 | 115 | store._window_auto = True 116 | delay = yield 117 | pause(delay) 118 | 119 | yield None 120 | 121 | def message(sender, message, delay=None): 122 | dc = _discussion_coroutine() 123 | dc.send(None) 124 | 125 | sender = character(sender) 126 | formatted_message = remove_text_tags(message) 127 | 128 | dc.send(_Payload(sender.key, formatted_message, TEXT)) 129 | dc.send(sender.get_typing_delay(formatted_message)) 130 | 131 | register_message(_group_chat, sender, message) 132 | 133 | dc.send(delay) 134 | 135 | def register_message(group, sender, text): 136 | _check_for_tags(text) 137 | 138 | group = group_chat(group) 139 | sender = character(sender) 140 | 141 | p = _Payload(sender.key, text, TEXT) 142 | group._save_payload(p) 143 | _run_callbacks(group, "save", p) 144 | 145 | def image(sender, image, time=2.0, delay=None): 146 | dc = _discussion_coroutine() 147 | dc.send(None) 148 | 149 | sender = character(sender) 150 | 151 | dc.send(_Payload(sender.key, image, IMAGE)) 152 | dc.send(time) 153 | 154 | register_image(_group_chat, sender, image) 155 | 156 | dc.send(delay) 157 | 158 | def register_image(group, sender, image): 159 | group = group_chat(group) 160 | sender = character(sender) 161 | 162 | p = _Payload(sender.key, image, IMAGE) 163 | group._save_payload(p) 164 | _run_callbacks(group, "save", p) 165 | 166 | def label(label, delay=0.5): 167 | dc = _discussion_coroutine() 168 | dc.send(None) 169 | dc.send(_Payload(None, label, LABEL)) 170 | dc.send(-1) 171 | 172 | register_label(_group_chat, label) 173 | 174 | dc.send(delay) 175 | 176 | def register_label(group, label): 177 | _check_for_tags(label) 178 | 179 | group = group_chat(group) 180 | 181 | p = _Payload(None, label, LABEL) 182 | group._save_payload(p, False) 183 | _run_callbacks(group, "save", p) 184 | 185 | def _register_date(group, month, day, year, hour, minute, second): 186 | group = group_chat(group) 187 | 188 | if (group.date.year, group.date.month, group.date.day) < (year, month, day): 189 | group._save_payload(_Payload(None, format_date(month, day, year), DATE), False) 190 | 191 | group.date = datetime.datetime(year=year, month=month, day=day, hour=hour, minute=minute, second=second) 192 | group._save_payload(_Payload(None, format_time(hour, minute), DATE), False) 193 | 194 | _run_callbacks(group, "save", _Payload(None, (month, day, year, hour, minute, second), LABEL)) 195 | 196 | def _get_date(group, month, day, year, hour, minute, second, auto): 197 | group = group_chat(group) 198 | 199 | current_gc_date = group.date 200 | current_date = phone.system.get_date() 201 | 202 | if auto: 203 | month = year = day = hour = minute = second = True 204 | 205 | if month is None: month = current_gc_date.month 206 | elif month is True: month = current_date.month 207 | 208 | if day is None: day = current_gc_date.day 209 | elif day is True: day = current_date.day 210 | 211 | if year is None: year = current_gc_date.year 212 | elif year is True: year = current_date.year 213 | 214 | if hour is None: hour = current_gc_date.hour 215 | elif hour is True: hour = current_date.hour 216 | 217 | if minute is None: minute = current_gc_date.minute 218 | elif minute is True: minute = current_date.minute 219 | 220 | if second is None: second = current_gc_date.second 221 | elif second is True: second = current_date.second 222 | 223 | return (month, day, year, hour, minute, second) 224 | 225 | def date(month, day, year, hour, minute, second, delay=0.5, auto=False): 226 | dc = _discussion_coroutine() 227 | dc.send(None) 228 | 229 | date_tuple = _get_date(_group_chat, month, day, year, hour, minute, second, auto) 230 | 231 | dc.send(_Payload(None, date_tuple, DATE)) 232 | dc.send(-1) 233 | 234 | _register_date(_group_chat, *date_tuple) 235 | 236 | dc.send(delay) 237 | 238 | def register_date(group, month, day, year, hour, minute, second, auto=False): 239 | _register_date(group, *_get_date(group, month, day, year, hour, minute, second, auto)) 240 | 241 | def typing(sender, value, delay=None): 242 | dc = _discussion_coroutine() 243 | dc.send(None) 244 | 245 | if isinstance(value, basestring): 246 | value = sender.get_typing_delay(value) 247 | 248 | dc.send(_Payload(sender.key, value, TYPING)) 249 | dc.send(value) 250 | dc.send(delay) 251 | 252 | def choice(captions, delay=0.3): 253 | dc = _discussion_coroutine() 254 | dc.send(None) 255 | dc.send(_Payload(None, captions, MENU)) 256 | 257 | rv = ui.interact() 258 | 259 | dc.send(delay) 260 | dc.send(-1) 261 | 262 | return captions.index(rv) 263 | 264 | def audio(sender, audio, time=2.0, delay=None): 265 | dc = _discussion_coroutine() 266 | dc.send(None) 267 | 268 | sender = character(sender) 269 | 270 | dc.send(_Payload(sender.key, audio, AUDIO)) 271 | dc.send(time) 272 | 273 | register_audio(_group_chat, sender, audio) 274 | 275 | dc.send(delay) 276 | 277 | def register_audio(group, sender, audio): 278 | if not isinstance(audio, basestring): 279 | raise TypeError("audio is expected to be a string") 280 | 281 | group = group_chat(group) 282 | sender = character(sender) 283 | 284 | p = _Payload(sender.key, audio, AUDIO) 285 | group._save_payload(p) 286 | _run_callbacks(group, "save", p) 287 | 288 | _yadjustment = ui.adjustment() 289 | 290 | default -100 phone.discussion._current_payload = None 291 | default -100 phone.discussion._group_chat = None 292 | 293 | python early in phone.discussion._PayloadTypes: # fake enum because of the module not existing in python 2.7 (it's a 3.4 thing) 294 | TYPING = 0 295 | TEXT = 1 296 | IMAGE = 2 297 | LABEL = 3 298 | DATE = 4 299 | MENU = 5 300 | AUDIO = 6 301 | VIDEO = 7 302 | 303 | ALL = (TYPING, TEXT, IMAGE, LABEL, DATE, MENU, AUDIO, VIDEO) 304 | 305 | renpy.store.phone.discussion.TYPING = TYPING 306 | renpy.store.phone.discussion.TEXT = TEXT 307 | renpy.store.phone.discussion.IMAGE = IMAGE 308 | renpy.store.phone.discussion.LABEL = LABEL 309 | renpy.store.phone.discussion.DATE = DATE 310 | renpy.store.phone.discussion.MENU = MENU 311 | renpy.store.phone.discussion.AUDIO = AUDIO 312 | renpy.store.phone.discussion.VIDEO = VIDEO 313 | 314 | _constant = True 315 | 316 | init python in phone.discussion: 317 | from store.phone.group_chat import group_chat 318 | from store.phone.character import character 319 | 320 | init 1400 python in phone: 321 | @renpy.partial(execute_default, id="__sort_register_messages") 322 | def __sort_register_messages(): 323 | global data 324 | for key in data: 325 | discussion.sort_messages(key) -------------------------------------------------------------------------------- /phone/apps/discussion/group_chats.rpy: -------------------------------------------------------------------------------- 1 | init -100 python in phone.group_chat: 2 | from renpy.store import store, phone 3 | import datetime 4 | 5 | config = phone.config 6 | 7 | class GroupChat(object): 8 | transient = False 9 | _unread = True 10 | 11 | def __init__(self, name, icon, key, transient=False): 12 | global _group_chats 13 | _group_chats[key] = self 14 | 15 | self.name = name 16 | self.icon = icon 17 | self.date = datetime.datetime(year=1970, month=1, day=1, hour=0, minute=0) 18 | self.transient = transient 19 | 20 | self._unread = True 21 | 22 | self._characters = set() 23 | self._payloads = [ ] 24 | self._page = 0 25 | 26 | if key is None: raise ValueError("key may not be 'None'") 27 | self.key = key 28 | 29 | # deprecated 30 | self.short_name = name 31 | 32 | @property 33 | def unread(self): 34 | if not config.unread_group_chat_pov: 35 | return self._unread 36 | return phone.data[store.pov_key]["group_chat_unread_pov"].setdefault(self.key, True) 37 | 38 | @unread.setter 39 | def unread(self, v): 40 | if not config.unread_group_chat_pov: 41 | self._unread = v 42 | else: 43 | phone.data[store.pov_key]["group_chat_unread_pov"][self.key] = v 44 | 45 | def add_character(self, char): 46 | if isinstance(char, list): 47 | for c in char: 48 | self.add_character(c) 49 | else: 50 | char = character(char).key 51 | self._characters.add(char) 52 | 53 | if self.key not in phone.data[char]["group_chats"]: 54 | phone.data[char]["group_chats"].append(self.key) 55 | 56 | return self 57 | 58 | def remove_character(self, char): 59 | char = character(char).key 60 | if char not in self._characters: return 61 | self._characters.remove(char) 62 | 63 | phone.data[char]["group_chats"].remove(self.key) 64 | 65 | def number_of_messages_sent(self, char): 66 | if char is not None: key = charcter(char).key 67 | else: key = char 68 | 69 | rv = 0 70 | for p in self._payloads: 71 | if (p.type in (_PayloadTypes.TEXT, _PayloadTypes.IMAGE, _PayloadTypes.AUDIO, _PayloadTypes.VIDEO) 72 | and (key is None or p.source == key) 73 | ): rv += 1 74 | return rv 75 | 76 | @property 77 | def number_of_messages(self): 78 | return self.number_of_messages_sent(None) 79 | 80 | def clear(self): 81 | self._payloads.clear() 82 | 83 | def _can_load_more(self): 84 | if not self._payloads: return False 85 | return self._get_messages()[0] is not self._payloads[0] 86 | 87 | def _get_messages(self): 88 | messages_displayed = config.messages_displayed 89 | 90 | min_x = self._page * messages_displayed 91 | max_x = min_x + messages_displayed 92 | 93 | l = len(self._payloads) 94 | 95 | remaining = l - max_x 96 | if remaining <= config.messages_fill_if_lower: 97 | max_x += remaining 98 | 99 | return self._payloads[l-max_x:l-min_x] 100 | 101 | @property 102 | def _date_text(self): 103 | date = self.date 104 | return format_date(date.month, date.day, date.year) 105 | 106 | @property 107 | def _hour_text(self): 108 | date = self.date 109 | return format_time(date.hour, date.minute) 110 | 111 | def _save_payload(self, p, check_source=True): 112 | if check_source and p.source not in self._characters: 113 | raise Exception("sender '{}' isn't in group chat".format(p.source)) 114 | 115 | if p.type == _PayloadTypes.TYPING: 116 | raise Exception("can't save typing") 117 | elif p.type == _PayloadTypes.MENU: 118 | raise Exception("can't save menu") 119 | 120 | self._payloads.append(p) 121 | 122 | self.unread = phone.discussion._group_chat is not self 123 | 124 | def _page_up(self): 125 | self._page += 1 126 | 127 | def _page_down(self): 128 | self._page -= 1 129 | 130 | def __iter__(self): 131 | return reversed(self._payloads) 132 | 133 | def __len__(self): 134 | return len(self._payloads) 135 | 136 | def __hash__(self): 137 | return hash(self.key) 138 | 139 | def group_chat(x): 140 | if isinstance(x, GroupChat): return x 141 | if not has_group_chat(x): 142 | raise KeyError("no group chat with the key %r exists (check your definitions)" % x) 143 | return _group_chats[x] 144 | 145 | def has_group_chat(key): 146 | return key in _group_chats 147 | 148 | def get_all(): 149 | return list(_group_chats.values()) 150 | 151 | default -100 phone.group_chat._group_chats = { } 152 | 153 | init python in phone.group_chat: 154 | from store.phone.character import character 155 | from store.phone.discussion import _PayloadTypes, remove_text_tags 156 | from store.phone import format_time, format_date -------------------------------------------------------------------------------- /phone/apps/discussion/typing.rpy: -------------------------------------------------------------------------------- 1 | transform _phone_message_typing(delay): 2 | alpha 0.25 3 | pause delay 4 | 5 | block: 6 | ease 0.2 alpha 0.75 7 | pause 0.2 8 | ease 0.2 alpha 0.25 9 | pause 0.6 10 | repeat 11 | 12 | screen _phone_message_typing(sender): 13 | style_prefix "phone_typing" 14 | 15 | hbox: 16 | frame: 17 | hbox: 18 | text "⚫" at _phone_message_typing(0.0) 19 | text "⚫" at _phone_message_typing(0.2) 20 | text "⚫" at _phone_message_typing(0.4) 21 | 22 | text __("{short_name} is typing...").format(short_name=phone.short_name(sender.name, 9)) style "phone_typing_istyping" yalign 0.5 23 | 24 | style phone_typing_hbox is empty: 25 | spacing 3 26 | 27 | style phone_typing_frame is phone_messages_frame: 28 | background phone.character.get_textbox("#f2f2f2") 29 | 30 | style phone_typing_text is phone_messages_text: 31 | color "#000" 32 | font "DejaVuSans.ttf" 33 | 34 | style phone_typing_istyping is empty: 35 | color "#626262" 36 | outlines [ ] 37 | size 16 38 | font phone.asset("Aller_Rg.ttf") 39 | 40 | init python: 41 | if is_renpy_version_or_above(7, 7, 0): 42 | style.phone_typing_text.emoji_font = None -------------------------------------------------------------------------------- /phone/assets/Aller_Rg.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/Aller_Rg.ttf -------------------------------------------------------------------------------- /phone/assets/JetBrainsMono-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/JetBrainsMono-ExtraBold.ttf -------------------------------------------------------------------------------- /phone/assets/JetBrainsMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/JetBrainsMono-Regular.ttf -------------------------------------------------------------------------------- /phone/assets/Metropolis-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/Metropolis-Regular.otf -------------------------------------------------------------------------------- /phone/assets/airplane_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/airplane_icon.png -------------------------------------------------------------------------------- /phone/assets/arrow_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/arrow_icon.png -------------------------------------------------------------------------------- /phone/assets/audio_message_wave_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/audio_message_wave_icon.png -------------------------------------------------------------------------------- /phone/assets/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/background.png -------------------------------------------------------------------------------- /phone/assets/bluetooth_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/bluetooth_icon.png -------------------------------------------------------------------------------- /phone/assets/calculator_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/calculator_icon.png -------------------------------------------------------------------------------- /phone/assets/call_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/call_icon.png -------------------------------------------------------------------------------- /phone/assets/camera_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/camera_icon.png -------------------------------------------------------------------------------- /phone/assets/cellular_data_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/cellular_data_icon.png -------------------------------------------------------------------------------- /phone/assets/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/circle.png -------------------------------------------------------------------------------- /phone/assets/default_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/default_icon.png -------------------------------------------------------------------------------- /phone/assets/emojis/2hearts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/2hearts.png -------------------------------------------------------------------------------- /phone/assets/emojis/4k.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/4k.png -------------------------------------------------------------------------------- /phone/assets/emojis/Aika.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/Aika.png -------------------------------------------------------------------------------- /phone/assets/emojis/AikaEmbarassed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/AikaEmbarassed.png -------------------------------------------------------------------------------- /phone/assets/emojis/AikaJoy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/AikaJoy.png -------------------------------------------------------------------------------- /phone/assets/emojis/Amelia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/Amelia.png -------------------------------------------------------------------------------- /phone/assets/emojis/AmeliaBreh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/AmeliaBreh.png -------------------------------------------------------------------------------- /phone/assets/emojis/AmeliaPog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/AmeliaPog.png -------------------------------------------------------------------------------- /phone/assets/emojis/AmeliaPout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/AmeliaPout.png -------------------------------------------------------------------------------- /phone/assets/emojis/AmeliaTheRock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/AmeliaTheRock.png -------------------------------------------------------------------------------- /phone/assets/emojis/AmeliaUwaaa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/AmeliaUwaaa.png -------------------------------------------------------------------------------- /phone/assets/emojis/Ellen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/Ellen.png -------------------------------------------------------------------------------- /phone/assets/emojis/EllenBruh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/EllenBruh.png -------------------------------------------------------------------------------- /phone/assets/emojis/EllenPog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/EllenPog.png -------------------------------------------------------------------------------- /phone/assets/emojis/EllenPout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/EllenPout.png -------------------------------------------------------------------------------- /phone/assets/emojis/EllenScream.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/EllenScream.png -------------------------------------------------------------------------------- /phone/assets/emojis/Kaito.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/Kaito.png -------------------------------------------------------------------------------- /phone/assets/emojis/KaitoCrazy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/KaitoCrazy.png -------------------------------------------------------------------------------- /phone/assets/emojis/KaitoPunchingBag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/KaitoPunchingBag.png -------------------------------------------------------------------------------- /phone/assets/emojis/KaitoSorry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/KaitoSorry.png -------------------------------------------------------------------------------- /phone/assets/emojis/KaitoSurprised.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/KaitoSurprised.png -------------------------------------------------------------------------------- /phone/assets/emojis/Melody.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/Melody.png -------------------------------------------------------------------------------- /phone/assets/emojis/MelodyClown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/MelodyClown.png -------------------------------------------------------------------------------- /phone/assets/emojis/MelodyCryingAboutIt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/MelodyCryingAboutIt.png -------------------------------------------------------------------------------- /phone/assets/emojis/MelodyPout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/MelodyPout.png -------------------------------------------------------------------------------- /phone/assets/emojis/MelodySmug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/MelodySmug.png -------------------------------------------------------------------------------- /phone/assets/emojis/MelodyTeehee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/MelodyTeehee.png -------------------------------------------------------------------------------- /phone/assets/emojis/MelodyThink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/MelodyThink.png -------------------------------------------------------------------------------- /phone/assets/emojis/MelodyUwU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/MelodyUwU.png -------------------------------------------------------------------------------- /phone/assets/emojis/MelodyUwaaa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/MelodyUwaaa.png -------------------------------------------------------------------------------- /phone/assets/emojis/andioop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/andioop.png -------------------------------------------------------------------------------- /phone/assets/emojis/angry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/angry.png -------------------------------------------------------------------------------- /phone/assets/emojis/animeangry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/animeangry.png -------------------------------------------------------------------------------- /phone/assets/emojis/bandage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/bandage.png -------------------------------------------------------------------------------- /phone/assets/emojis/barf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/barf.png -------------------------------------------------------------------------------- /phone/assets/emojis/blueheart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/blueheart.png -------------------------------------------------------------------------------- /phone/assets/emojis/blush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/blush.png -------------------------------------------------------------------------------- /phone/assets/emojis/book1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/book1.png -------------------------------------------------------------------------------- /phone/assets/emojis/book2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/book2.png -------------------------------------------------------------------------------- /phone/assets/emojis/book3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/book3.png -------------------------------------------------------------------------------- /phone/assets/emojis/book4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/book4.png -------------------------------------------------------------------------------- /phone/assets/emojis/book5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/book5.png -------------------------------------------------------------------------------- /phone/assets/emojis/book6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/book6.png -------------------------------------------------------------------------------- /phone/assets/emojis/books.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/books.png -------------------------------------------------------------------------------- /phone/assets/emojis/brownheart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/brownheart.png -------------------------------------------------------------------------------- /phone/assets/emojis/bruh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/bruh.png -------------------------------------------------------------------------------- /phone/assets/emojis/brush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/brush.png -------------------------------------------------------------------------------- /phone/assets/emojis/bull.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/bull.png -------------------------------------------------------------------------------- /phone/assets/emojis/call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/call.png -------------------------------------------------------------------------------- /phone/assets/emojis/callme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/callme.png -------------------------------------------------------------------------------- /phone/assets/emojis/cap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/cap.png -------------------------------------------------------------------------------- /phone/assets/emojis/clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/clock.png -------------------------------------------------------------------------------- /phone/assets/emojis/clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/clouds.png -------------------------------------------------------------------------------- /phone/assets/emojis/clown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/clown.png -------------------------------------------------------------------------------- /phone/assets/emojis/cold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/cold.png -------------------------------------------------------------------------------- /phone/assets/emojis/cookie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/cookie.png -------------------------------------------------------------------------------- /phone/assets/emojis/cowboy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/cowboy.png -------------------------------------------------------------------------------- /phone/assets/emojis/crazy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/crazy.png -------------------------------------------------------------------------------- /phone/assets/emojis/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/cross.png -------------------------------------------------------------------------------- /phone/assets/emojis/crown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/crown.png -------------------------------------------------------------------------------- /phone/assets/emojis/cry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/cry.png -------------------------------------------------------------------------------- /phone/assets/emojis/darkheart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/darkheart.png -------------------------------------------------------------------------------- /phone/assets/emojis/dead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/dead.png -------------------------------------------------------------------------------- /phone/assets/emojis/depress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/depress.png -------------------------------------------------------------------------------- /phone/assets/emojis/disguise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/disguise.png -------------------------------------------------------------------------------- /phone/assets/emojis/dizzy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/dizzy.png -------------------------------------------------------------------------------- /phone/assets/emojis/donut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/donut.png -------------------------------------------------------------------------------- /phone/assets/emojis/drool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/drool.png -------------------------------------------------------------------------------- /phone/assets/emojis/drop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/drop.png -------------------------------------------------------------------------------- /phone/assets/emojis/ear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/ear.png -------------------------------------------------------------------------------- /phone/assets/emojis/eggplant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/eggplant.png -------------------------------------------------------------------------------- /phone/assets/emojis/ehehe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/ehehe.png -------------------------------------------------------------------------------- /phone/assets/emojis/ehh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/ehh.png -------------------------------------------------------------------------------- /phone/assets/emojis/exhale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/exhale.png -------------------------------------------------------------------------------- /phone/assets/emojis/eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/eye.png -------------------------------------------------------------------------------- /phone/assets/emojis/eyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/eyes.png -------------------------------------------------------------------------------- /phone/assets/emojis/eyesclosedsmile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/eyesclosedsmile.png -------------------------------------------------------------------------------- /phone/assets/emojis/fire.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/fire.png -------------------------------------------------------------------------------- /phone/assets/emojis/fist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/fist.png -------------------------------------------------------------------------------- /phone/assets/emojis/fistl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/fistl.png -------------------------------------------------------------------------------- /phone/assets/emojis/fistr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/fistr.png -------------------------------------------------------------------------------- /phone/assets/emojis/fistup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/fistup.png -------------------------------------------------------------------------------- /phone/assets/emojis/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/flag.png -------------------------------------------------------------------------------- /phone/assets/emojis/food.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/food.png -------------------------------------------------------------------------------- /phone/assets/emojis/fuck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/fuck.png -------------------------------------------------------------------------------- /phone/assets/emojis/fuckyou.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/fuckyou.png -------------------------------------------------------------------------------- /phone/assets/emojis/goblin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/goblin.png -------------------------------------------------------------------------------- /phone/assets/emojis/grab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/grab.png -------------------------------------------------------------------------------- /phone/assets/emojis/grave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/grave.png -------------------------------------------------------------------------------- /phone/assets/emojis/greenheart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/greenheart.png -------------------------------------------------------------------------------- /phone/assets/emojis/guilty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/guilty.png -------------------------------------------------------------------------------- /phone/assets/emojis/halo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/halo.png -------------------------------------------------------------------------------- /phone/assets/emojis/hand1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/hand1.png -------------------------------------------------------------------------------- /phone/assets/emojis/hand2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/hand2.png -------------------------------------------------------------------------------- /phone/assets/emojis/hands.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/hands.png -------------------------------------------------------------------------------- /phone/assets/emojis/happy1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/happy1.png -------------------------------------------------------------------------------- /phone/assets/emojis/happy2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/happy2.png -------------------------------------------------------------------------------- /phone/assets/emojis/happy3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/happy3.png -------------------------------------------------------------------------------- /phone/assets/emojis/headphones.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/headphones.png -------------------------------------------------------------------------------- /phone/assets/emojis/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/heart.png -------------------------------------------------------------------------------- /phone/assets/emojis/hearteyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/hearteyes.png -------------------------------------------------------------------------------- /phone/assets/emojis/hearthand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/hearthand.png -------------------------------------------------------------------------------- /phone/assets/emojis/hearts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/hearts.png -------------------------------------------------------------------------------- /phone/assets/emojis/heartshine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/heartshine.png -------------------------------------------------------------------------------- /phone/assets/emojis/hey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/hey.png -------------------------------------------------------------------------------- /phone/assets/emojis/hiding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/hiding.png -------------------------------------------------------------------------------- /phone/assets/emojis/highfive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/highfive.png -------------------------------------------------------------------------------- /phone/assets/emojis/hold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/hold.png -------------------------------------------------------------------------------- /phone/assets/emojis/hot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/hot.png -------------------------------------------------------------------------------- /phone/assets/emojis/hug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/hug.png -------------------------------------------------------------------------------- /phone/assets/emojis/ididit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/ididit.png -------------------------------------------------------------------------------- /phone/assets/emojis/imp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/imp.png -------------------------------------------------------------------------------- /phone/assets/emojis/italian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/italian.png -------------------------------------------------------------------------------- /phone/assets/emojis/kill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/kill.png -------------------------------------------------------------------------------- /phone/assets/emojis/kiss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/kiss.png -------------------------------------------------------------------------------- /phone/assets/emojis/laugh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/laugh.png -------------------------------------------------------------------------------- /phone/assets/emojis/lipbite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/lipbite.png -------------------------------------------------------------------------------- /phone/assets/emojis/lips.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/lips.png -------------------------------------------------------------------------------- /phone/assets/emojis/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/mask.png -------------------------------------------------------------------------------- /phone/assets/emojis/meh1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/meh1.png -------------------------------------------------------------------------------- /phone/assets/emojis/meh2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/meh2.png -------------------------------------------------------------------------------- /phone/assets/emojis/melt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/melt.png -------------------------------------------------------------------------------- /phone/assets/emojis/mindblown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/mindblown.png -------------------------------------------------------------------------------- /phone/assets/emojis/moan1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/moan1.png -------------------------------------------------------------------------------- /phone/assets/emojis/moan2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/moan2.png -------------------------------------------------------------------------------- /phone/assets/emojis/money.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/money.png -------------------------------------------------------------------------------- /phone/assets/emojis/moon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/moon.png -------------------------------------------------------------------------------- /phone/assets/emojis/morning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/morning.png -------------------------------------------------------------------------------- /phone/assets/emojis/music1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/music1.png -------------------------------------------------------------------------------- /phone/assets/emojis/music2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/music2.png -------------------------------------------------------------------------------- /phone/assets/emojis/nerd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/nerd.png -------------------------------------------------------------------------------- /phone/assets/emojis/nomouth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/nomouth.png -------------------------------------------------------------------------------- /phone/assets/emojis/nose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/nose.png -------------------------------------------------------------------------------- /phone/assets/emojis/nut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/nut.png -------------------------------------------------------------------------------- /phone/assets/emojis/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/ok.png -------------------------------------------------------------------------------- /phone/assets/emojis/okay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/okay.png -------------------------------------------------------------------------------- /phone/assets/emojis/oop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/oop.png -------------------------------------------------------------------------------- /phone/assets/emojis/openbook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/openbook.png -------------------------------------------------------------------------------- /phone/assets/emojis/orangeheart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/orangeheart.png -------------------------------------------------------------------------------- /phone/assets/emojis/palms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/palms.png -------------------------------------------------------------------------------- /phone/assets/emojis/party.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/party.png -------------------------------------------------------------------------------- /phone/assets/emojis/peace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/peace.png -------------------------------------------------------------------------------- /phone/assets/emojis/peach.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/peach.png -------------------------------------------------------------------------------- /phone/assets/emojis/peekaboo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/peekaboo.png -------------------------------------------------------------------------------- /phone/assets/emojis/pen1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/pen1.png -------------------------------------------------------------------------------- /phone/assets/emojis/pen2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/pen2.png -------------------------------------------------------------------------------- /phone/assets/emojis/pen3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/pen3.png -------------------------------------------------------------------------------- /phone/assets/emojis/pencil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/pencil.png -------------------------------------------------------------------------------- /phone/assets/emojis/piano.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/piano.png -------------------------------------------------------------------------------- /phone/assets/emojis/pinch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/pinch.png -------------------------------------------------------------------------------- /phone/assets/emojis/plead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/plead.png -------------------------------------------------------------------------------- /phone/assets/emojis/plsno1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/plsno1.png -------------------------------------------------------------------------------- /phone/assets/emojis/plsno2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/plsno2.png -------------------------------------------------------------------------------- /phone/assets/emojis/poems.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/poems.png -------------------------------------------------------------------------------- /phone/assets/emojis/pointl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/pointl.png -------------------------------------------------------------------------------- /phone/assets/emojis/pointr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/pointr.png -------------------------------------------------------------------------------- /phone/assets/emojis/pointup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/pointup.png -------------------------------------------------------------------------------- /phone/assets/emojis/pointupagain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/pointupagain.png -------------------------------------------------------------------------------- /phone/assets/emojis/pray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/pray.png -------------------------------------------------------------------------------- /phone/assets/emojis/proud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/proud.png -------------------------------------------------------------------------------- /phone/assets/emojis/pucker1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/pucker1.png -------------------------------------------------------------------------------- /phone/assets/emojis/pucker2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/pucker2.png -------------------------------------------------------------------------------- /phone/assets/emojis/pucker3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/pucker3.png -------------------------------------------------------------------------------- /phone/assets/emojis/purpleheart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/purpleheart.png -------------------------------------------------------------------------------- /phone/assets/emojis/rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/rain.png -------------------------------------------------------------------------------- /phone/assets/emojis/raisedeyebrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/raisedeyebrow.png -------------------------------------------------------------------------------- /phone/assets/emojis/redangry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/redangry.png -------------------------------------------------------------------------------- /phone/assets/emojis/regret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/regret.png -------------------------------------------------------------------------------- /phone/assets/emojis/research.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/research.png -------------------------------------------------------------------------------- /phone/assets/emojis/rock1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/rock1.png -------------------------------------------------------------------------------- /phone/assets/emojis/rock2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/rock2.png -------------------------------------------------------------------------------- /phone/assets/emojis/rollseyes1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/rollseyes1.png -------------------------------------------------------------------------------- /phone/assets/emojis/rollseyes2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/rollseyes2.png -------------------------------------------------------------------------------- /phone/assets/emojis/sad1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/sad1.png -------------------------------------------------------------------------------- /phone/assets/emojis/sad2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/sad2.png -------------------------------------------------------------------------------- /phone/assets/emojis/sad3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/sad3.png -------------------------------------------------------------------------------- /phone/assets/emojis/salute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/salute.png -------------------------------------------------------------------------------- /phone/assets/emojis/shake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/shake.png -------------------------------------------------------------------------------- /phone/assets/emojis/shakel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/shakel.png -------------------------------------------------------------------------------- /phone/assets/emojis/shaker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/shaker.png -------------------------------------------------------------------------------- /phone/assets/emojis/shh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/shh.png -------------------------------------------------------------------------------- /phone/assets/emojis/shock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/shock.png -------------------------------------------------------------------------------- /phone/assets/emojis/shook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/shook.png -------------------------------------------------------------------------------- /phone/assets/emojis/sick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/sick.png -------------------------------------------------------------------------------- /phone/assets/emojis/skull1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/skull1.png -------------------------------------------------------------------------------- /phone/assets/emojis/skull2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/skull2.png -------------------------------------------------------------------------------- /phone/assets/emojis/sleep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/sleep.png -------------------------------------------------------------------------------- /phone/assets/emojis/smile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/smile.png -------------------------------------------------------------------------------- /phone/assets/emojis/sneeze.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/sneeze.png -------------------------------------------------------------------------------- /phone/assets/emojis/snooty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/snooty.png -------------------------------------------------------------------------------- /phone/assets/emojis/snooze.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/snooze.png -------------------------------------------------------------------------------- /phone/assets/emojis/sob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/sob.png -------------------------------------------------------------------------------- /phone/assets/emojis/sorry1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/sorry1.png -------------------------------------------------------------------------------- /phone/assets/emojis/sorry2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/sorry2.png -------------------------------------------------------------------------------- /phone/assets/emojis/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/star.png -------------------------------------------------------------------------------- /phone/assets/emojis/stareyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/stareyes.png -------------------------------------------------------------------------------- /phone/assets/emojis/strong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/strong.png -------------------------------------------------------------------------------- /phone/assets/emojis/sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/sun.png -------------------------------------------------------------------------------- /phone/assets/emojis/sunglasses.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/sunglasses.png -------------------------------------------------------------------------------- /phone/assets/emojis/surprise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/surprise.png -------------------------------------------------------------------------------- /phone/assets/emojis/talleyeshappy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/talleyeshappy.png -------------------------------------------------------------------------------- /phone/assets/emojis/tasty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/tasty.png -------------------------------------------------------------------------------- /phone/assets/emojis/think.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/think.png -------------------------------------------------------------------------------- /phone/assets/emojis/thumbsdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/thumbsdown.png -------------------------------------------------------------------------------- /phone/assets/emojis/thumbsup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/thumbsup.png -------------------------------------------------------------------------------- /phone/assets/emojis/tongue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/tongue.png -------------------------------------------------------------------------------- /phone/assets/emojis/tonguewink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/tonguewink.png -------------------------------------------------------------------------------- /phone/assets/emojis/tonguexd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/tonguexd.png -------------------------------------------------------------------------------- /phone/assets/emojis/uhoh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/uhoh.png -------------------------------------------------------------------------------- /phone/assets/emojis/unimpressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/unimpressed.png -------------------------------------------------------------------------------- /phone/assets/emojis/upsidedown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/upsidedown.png -------------------------------------------------------------------------------- /phone/assets/emojis/veryworried.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/veryworried.png -------------------------------------------------------------------------------- /phone/assets/emojis/wave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/wave.png -------------------------------------------------------------------------------- /phone/assets/emojis/wet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/wet.png -------------------------------------------------------------------------------- /phone/assets/emojis/whiteheart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/whiteheart.png -------------------------------------------------------------------------------- /phone/assets/emojis/why.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/why.png -------------------------------------------------------------------------------- /phone/assets/emojis/wink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/wink.png -------------------------------------------------------------------------------- /phone/assets/emojis/worried1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/worried1.png -------------------------------------------------------------------------------- /phone/assets/emojis/worried2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/worried2.png -------------------------------------------------------------------------------- /phone/assets/emojis/writing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/writing.png -------------------------------------------------------------------------------- /phone/assets/emojis/wrong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/wrong.png -------------------------------------------------------------------------------- /phone/assets/emojis/xd1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/xd1.png -------------------------------------------------------------------------------- /phone/assets/emojis/xd2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/xd2.png -------------------------------------------------------------------------------- /phone/assets/emojis/xd3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/xd3.png -------------------------------------------------------------------------------- /phone/assets/emojis/yawn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/yawn.png -------------------------------------------------------------------------------- /phone/assets/emojis/yellowheart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/yellowheart.png -------------------------------------------------------------------------------- /phone/assets/emojis/you.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/you.png -------------------------------------------------------------------------------- /phone/assets/emojis/zipped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/zipped.png -------------------------------------------------------------------------------- /phone/assets/emojis/zzz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/emojis/zzz.png -------------------------------------------------------------------------------- /phone/assets/flashlight_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/flashlight_icon.png -------------------------------------------------------------------------------- /phone/assets/hang_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/hang_up.png -------------------------------------------------------------------------------- /phone/assets/mc_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/mc_icon.png -------------------------------------------------------------------------------- /phone/assets/message_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/message_icon.png -------------------------------------------------------------------------------- /phone/assets/monika_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/monika_icon.png -------------------------------------------------------------------------------- /phone/assets/moon_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/moon_icon.png -------------------------------------------------------------------------------- /phone/assets/natsuki_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/natsuki_icon.png -------------------------------------------------------------------------------- /phone/assets/pause_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/pause_icon.png -------------------------------------------------------------------------------- /phone/assets/play_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/play_icon.png -------------------------------------------------------------------------------- /phone/assets/quick_menu_afm_idle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/quick_menu_afm_idle.png -------------------------------------------------------------------------------- /phone/assets/quick_menu_afm_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/quick_menu_afm_selected.png -------------------------------------------------------------------------------- /phone/assets/quick_menu_history_idle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/quick_menu_history_idle.png -------------------------------------------------------------------------------- /phone/assets/quick_menu_history_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/quick_menu_history_selected.png -------------------------------------------------------------------------------- /phone/assets/quick_menu_load_idle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/quick_menu_load_idle.png -------------------------------------------------------------------------------- /phone/assets/quick_menu_load_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/quick_menu_load_selected.png -------------------------------------------------------------------------------- /phone/assets/quick_menu_save_idle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/quick_menu_save_idle.png -------------------------------------------------------------------------------- /phone/assets/quick_menu_save_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/quick_menu_save_selected.png -------------------------------------------------------------------------------- /phone/assets/quick_menu_settings_idle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/quick_menu_settings_idle.png -------------------------------------------------------------------------------- /phone/assets/quick_menu_settings_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/quick_menu_settings_selected.png -------------------------------------------------------------------------------- /phone/assets/quick_menu_skip_idle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/quick_menu_skip_idle.png -------------------------------------------------------------------------------- /phone/assets/quick_menu_skip_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/quick_menu_skip_selected.png -------------------------------------------------------------------------------- /phone/assets/rotation_locked_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/rotation_locked_icon.png -------------------------------------------------------------------------------- /phone/assets/rotation_unlocked_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/rotation_unlocked_icon.png -------------------------------------------------------------------------------- /phone/assets/sayori_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/sayori_icon.png -------------------------------------------------------------------------------- /phone/assets/screen_mirroring_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/screen_mirroring_icon.png -------------------------------------------------------------------------------- /phone/assets/status_bar_battery_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/status_bar_battery_empty.png -------------------------------------------------------------------------------- /phone/assets/status_bar_battery_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/status_bar_battery_full.png -------------------------------------------------------------------------------- /phone/assets/status_bar_battery_half.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/status_bar_battery_half.png -------------------------------------------------------------------------------- /phone/assets/status_bar_battery_nine_tenth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/status_bar_battery_nine_tenth.png -------------------------------------------------------------------------------- /phone/assets/status_bar_battery_one_fourth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/status_bar_battery_one_fourth.png -------------------------------------------------------------------------------- /phone/assets/status_bar_battery_three_fourth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/status_bar_battery_three_fourth.png -------------------------------------------------------------------------------- /phone/assets/sun_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/sun_icon.png -------------------------------------------------------------------------------- /phone/assets/timer_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/timer_icon.png -------------------------------------------------------------------------------- /phone/assets/volume_icon_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/volume_icon_0.png -------------------------------------------------------------------------------- /phone/assets/volume_icon_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/volume_icon_1.png -------------------------------------------------------------------------------- /phone/assets/volume_icon_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/volume_icon_2.png -------------------------------------------------------------------------------- /phone/assets/wifi_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/wifi_icon.png -------------------------------------------------------------------------------- /phone/assets/yuri_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Elckarow/Better-EMR-Phone/c017f0fffef0d101bbf5b5a10bb020a125182bf2/phone/assets/yuri_icon.png -------------------------------------------------------------------------------- /phone/characters.rpy: -------------------------------------------------------------------------------- 1 | init -100 python in phone.character: 2 | from renpy.store import store, Color, __, RoundedCorners, phone 3 | from store.phone import config 4 | 5 | class Character(object): 6 | def __init__(self, name, icon, key, cps, color): 7 | _characters[key] = self 8 | 9 | self.name = name 10 | self.icon = icon 11 | 12 | self.cps = int(cps) 13 | self.color = Color(color) 14 | 15 | if key is None: raise ValueError("key may not be 'None'") 16 | self.key = key 17 | 18 | # deprecated 19 | self.short_name = name 20 | 21 | def get_textbox(self): 22 | return get_textbox(self.color) 23 | 24 | @property 25 | def is_pov(self): 26 | return self.key == store.pov_key 27 | 28 | def get_typing_delay(self, message, substitute=True, translate=True): 29 | if substitute: message = renpy.substitute(message, translate=translate) 30 | return (len(message) / self.cps) + config.message_delay 31 | 32 | def __hash__(self): 33 | return hash(self.key) 34 | 35 | def character(x): 36 | if isinstance(x, Character): return x 37 | if x is None: x = store.pov_key 38 | if not has_character(x): 39 | raise KeyError("no phone Character with the key %r exists (check your definitions)" % x) 40 | return _characters[x] 41 | 42 | def has_character(key): 43 | return key in _characters 44 | 45 | def get_textbox(color): 46 | return RoundedCorners(color, radius=config.textbox_radius) 47 | 48 | def get_all(): 49 | return list(_characters.values()) 50 | 51 | default phone.character._characters = { } -------------------------------------------------------------------------------- /phone/config.rpy: -------------------------------------------------------------------------------- 1 | python early in phone.config: 2 | from renpy.store import store, config as renpy_config, Dissolve, _warper, _, phone, Transform 3 | _constant = True 4 | 5 | # Where the assets are located. 6 | basedir = "phone/assets/" 7 | 8 | # A list of screen names. Those screens are shown above the phone screens (but still inside the phone). 9 | overlay_screens = [ ] 10 | 11 | # Do we use the game's quick menu or the phone's quick menu during phone calls? 12 | quick_menu = True 13 | 14 | # A transition used when showing the phone. 15 | enter_transition = Dissolve(0.6, time_warp=_warper.ease) 16 | 17 | # A transition used when hiding the phone. 18 | exit_transition = Dissolve(0.6, time_warp=_warper.ease) 19 | 20 | # A transition used when going from a phone screen to another. 21 | intra_transition = Dissolve(0.1) 22 | 23 | # A string used to format a time. Passed to `time.strftime`. 24 | time_format = _("%H:%M") 25 | 26 | # A string used to format a date. Passed to `datetime.datetime.strftime`. 27 | date_format = _("%m/%d/%Y") 28 | 29 | # The radius of the rounded corners of the textboxes. 30 | textbox_radius = 15 31 | 32 | # How many calls do we save? 33 | call_history_length = 20 34 | 35 | # A set of text tags that are allowed in text messages. 36 | # They should not change the size of the text. 37 | message_text_tags = { 38 | "emoji", "alpha", "color", "u", "i", "b", "a" 39 | } 40 | 41 | # Use the status bar? 42 | status_bar = True 43 | 44 | # Hide the status bar when any of those screens are showing. 45 | hide_status_bar_screens = [ ] 46 | 47 | # A dictionary mapping screen names to transforms or lists of transforms. 48 | # When a phone screen is shown, the screen name is looked up in the map (None is used if not found), 49 | # and the layer "master" is shown at those transforms. 50 | layer_at_transforms = { 51 | None: Transform(matrixcolor=renpy.display.matrix.Matrix([1, 0, 0, -0.03, # BrightnessMatrix(-0.03) 52 | 0, 1, 0, -0.03, 53 | 0, 0, 1, -0.03, 54 | 0, 0, 0, 1]), 55 | blur=2 56 | ) 57 | } 58 | 59 | # How many "pages" of application we use in the `phone` screen. 60 | applications_pages = 4 61 | 62 | # A dictionnary mapping a name to a callable. 63 | # Each *character* has an entry (their key) containing these values in the `phone.data` dictionnary. 64 | # When the entry is created, the callables are called without arguments, and the values are set. 65 | # tl;dr collections.defaultdict 66 | data = { 67 | "call_history": list, 68 | "group_chats": list, 69 | "background_image": lambda: None, 70 | "calendars": list, 71 | "group_chat_unread_pov": dict 72 | } 73 | 74 | def _generate_applications_dict(): 75 | rv = { 76 | i: phone.application._generate_applications_page() 77 | for i in range(applications_pages) 78 | } 79 | rv[None] = phone.application._generate_bottom_applications_page() 80 | rv["max"] = 0 81 | return rv 82 | 83 | data["applications"] = _generate_applications_dict 84 | 85 | # From 0.0 (complete darkness) to 1.0 (normal), how low can the brightness go? 86 | lowest_brightness = 0.3 87 | 88 | # A list of functions that are called whenever a phone discussion function executes. 89 | # They are called with three arguments: 90 | # -the *group chat* the interaction is taking place in. 91 | # -an event: 92 | # `"start"` is delivered at the start of the interaction. 93 | # `"end"` is delivered just before the data has been saved. 94 | # `"save"` is delivered after the data has been saved (called after the `register_` function associated to what's happening). 95 | # -an object representing the data, which has the following fields: 96 | # `source`, the *character* that's sending the data, or `None`. 97 | # `type`, one of the following constants (in the `phone.discussion` namespace): 98 | # `TYPING`, `TEXT`, `IMAGE`, `LABEL`, `DATE`, `MENU`, `AUDIO`, `VIDEO` (if it ever gets implemented). 99 | # `data`: 100 | # -For a typing, the time to wait for. 101 | # -For a text message, the text that's been formatted by `phone.discussion.remove_text_tags`. 102 | # -For an image, the displayable. 103 | # -For a label, the text. 104 | # -For a date, a tuple of (`month`, `day`, `year`, `hours`, `minutes`, `seconds`). 105 | # -For a menu, a list of all the captions. 106 | # -For an audio, the string of the audio. 107 | # -For a video, `None`. 108 | discussion_callbacks = [ ] 109 | 110 | # The name of the layer usied in video calls. It is appended to `config.detached_layers` 111 | video_call_layer = "phone_video_call" 112 | 113 | # A dict of transform properties applied to the `Layer` displayable used during a video call. 114 | video_call_layer_transform_properties = { 115 | "align": (0.5, 1.0), 116 | "ysize": 1.0, 117 | "fit": "contain" 118 | } 119 | 120 | # How many messages we display at the same time. 121 | messages_displayed = 100 122 | 123 | # If the next "load" of messages contains this many or less messages, add those messages to the current load. 124 | messages_fill_if_lower = 30 125 | 126 | # A number of seconds added to the pause before each message. 127 | message_delay = 0.6 128 | 129 | # An index. The default calendar used when the `phone_calendars` screen is shown. 130 | # If `True`, tries to retrieve the calendar that's in concordance to `phone.system.get_date()`. 131 | default_calendar_index = -1 132 | 133 | # If true, a group chat's "unreadness" is determined on the pov the group chat was read in. 134 | # I.e, if the group chat was read in the "mc" pov, then it won't be marked as read in the "s" pov. 135 | # If false, it is determined by whether the player has opened the group chat or not. 136 | unread_group_chat_pov = False 137 | 138 | # If true, will define all images found in "assets/emojis" as emojis. 139 | auto_emojis = True 140 | 141 | # The default value of the `delay` property for the `time` and `label` discussion statements. 142 | default_label_delay = 0.5 143 | 144 | python early: # prevent "default" 145 | config.special_namespaces["store.phone.config"] = type(config.special_namespaces["store.config"])(phone.config, "phone.config") 146 | 147 | init 1500 python in phone: 148 | @renpy_config.after_load_callbacks.append 149 | def __ensure_phone_data_entries(): 150 | changed = False 151 | for d in data.values(): 152 | for thing, f in config.data.items(): 153 | if thing not in d: 154 | d[thing] = f() 155 | changed = True 156 | if changed: 157 | renpy.block_rollback() -------------------------------------------------------------------------------- /phone/definitions/01definitions.rpy: -------------------------------------------------------------------------------- 1 | # /!\ default 2 | # pc as in phone character :monikk: 3 | default pc_sayori = phone.character.Character("Sayori", phone.asset("sayori_icon.png"), "s", 21, "#22Abf8") 4 | default pc_mc = phone.character.Character("MC", phone.asset("mc_icon.png"), "mc", 35, "#484848") 5 | default pc_yuri = phone.character.Character("Yuri", phone.asset("yuri_icon.png"), "y", 20, "#a327d6") 6 | default pc_monika = phone.character.Character("Monika", phone.asset("monika_icon.png"), "m", 40, "#0a0") 7 | default pc_natsuki = phone.character.Character("Natsuki", phone.asset("natsuki_icon.png"), "n", 45, "#fbb") 8 | 9 | default pov_key = "mc" 10 | 11 | define phone_s = Character("Sayori", screen="phone_say", who_style="phone_say_label", what_style="phone_say_dialogue") 12 | define phone_mc = Character("MC", screen="phone_say", who_style="phone_say_label", what_style="phone_say_dialogue") 13 | 14 | init 100 python in phone.application: 15 | add_app_to_all_characters(message_app) 16 | add_app_to_all_characters(call_history_app) 17 | add_app_to_all_characters(calendar_app) 18 | 19 | init 100 python in phone.calendar: 20 | add_calendar_to_all_characters(2023, 6, MONDAY) 21 | 22 | init phone register: 23 | define "Welcome": 24 | add "s" add "mc" add "y" add "m" add "n" 25 | icon phone.asset("default_icon.png") 26 | as thanks_for_using_my_framework key "ddu" 27 | 28 | label phone_discussion_test: 29 | phone discussion "ddu": 30 | time year 2023 month 6 day 5 hour 16 minute 30 delay -1 # exact date and time at which i wrote this. yes i am feeling quite silly and goofy 31 | label "'Sayori' has been added to the group" delay -1 32 | label "'MC' has been added to the group" delay -1 33 | label "'Yuri' has been added to the group" delay -1 34 | label "'Monika' has been added to the group" delay -1 35 | label "'Natsuki' has been added to the group" delay 0.2 36 | "m" "Hey there!" 37 | "n" "Thank you for using my framework." 38 | "n" "I mean {i}of course{/i} you're using {b}this{/b} framework." 39 | "n" "...not like there are any better ones out there~" 40 | "s" "natsuki!!!!! {emoji=EllenScream}" 41 | "s" "no being a meanie!!!!!!!{emoji=EllenScream}{emoji=EllenScream}{emoji=EllenScream}" 42 | "y" "If you are interested in DDLC mods, be sure to check out our mod {a=https://undercurrentsmod.weebly.com}Doki Doki Undercurrents{/a}! {emoji=Melody}" 43 | "mc" "In case you encounter an issue (or wanna make a suggestion)," 44 | "mc" "you can:" 45 | "mc" "DM me at {i}elckarow{/i} on Discord," 46 | "mc" "open an issue on {a=https://github.com/Elckarow/Better-EMR-Phone}GitHub{/a}," 47 | "mc" "make a post on the phone's {a=https://elckarow.itch.io/better-emr-phone}Itch page{/a}." 48 | "s" "Happy coding!" 49 | phone end discussion 50 | 51 | return 52 | 53 | label phone_call_test: 54 | phone call "s" 55 | phone_s "Ohayouuu!!!!!!!!!!!!!!!!" 56 | phone_mc "Hey!" 57 | "Why is she always this energetic?" 58 | phone end call 59 | "..." 60 | 61 | return -------------------------------------------------------------------------------- /phone/emojis.rpy: -------------------------------------------------------------------------------- 1 | init -150 python in phone.emojis: 2 | from renpy.store import store, Transform, phone, config as renpy_config 3 | from store.phone import config 4 | import os 5 | _constant = True 6 | 7 | import string 8 | _NOT_ALLOWED_CHARACTERS = set(string.punctuation.strip("_") + " ") 9 | 10 | _emojis = { } 11 | 12 | def add(name, emoji): 13 | global _NOT_ALLOWED_CHARACTERS 14 | if set(name) & _NOT_ALLOWED_CHARACTERS: 15 | raise Exception("not a valid emoji name: {}".format(name)) 16 | 17 | global _emojis 18 | _emojis[name] = renpy.displayable(emoji) 19 | 20 | def get(name): 21 | return _emojis[name] 22 | 23 | renpy_config.self_closing_custom_text_tags["emoji"] = \ 24 | lambda tag, name: [ 25 | (renpy.TEXT_DISPLAYABLE, Transform(get(name), subpixel=True, ysize=1.0, fit="contain")) 26 | ] 27 | 28 | import re 29 | _tag_pattern = re.compile(r"\{emoji\=([a-zA-Z0-9_]*)\}") 30 | 31 | def format_emoji_tag(s): 32 | for emoji in _tag_pattern.findall(s): s = _tag_pattern.sub(":" + emoji + ":", s, 1) 33 | return s 34 | 35 | init 1000 python hide in phone.emojis: 36 | if config.auto_emojis: 37 | emoji_base_path = phone.asset("emojis") 38 | 39 | try: 40 | for emoji in os.listdir(phone.path_join(renpy_config.basedir, "game", emoji_base_path)): 41 | path = phone.path_join(emoji_base_path, emoji) 42 | 43 | if os.path.isdir(phone.path_join(renpy_config.basedir, path)): 44 | continue 45 | 46 | name, extension = os.path.splitext(emoji) 47 | 48 | if extension.lower() not in renpy_config.image_extensions: 49 | continue 50 | 51 | add(name, path) 52 | 53 | except OSError: 54 | pass 55 | 56 | # prevent `default` 57 | python early in phone.emojis: 58 | pass 59 | 60 | python early: 61 | config.special_namespaces["store.phone.emojis"] = type(config.special_namespaces["store.config"])(phone.emojis, "phone.emojis") -------------------------------------------------------------------------------- /phone/overlay/click_effects.rpy: -------------------------------------------------------------------------------- 1 | screen _phone_click_effects(): 2 | default _effects = phone.click_effects.ClickEffects( 3 | phone_on_click_effect, 4 | phone_on_drag_effect, 5 | phone_on_release_effect 6 | ) 7 | add _effects 8 | 9 | define phone_click_uptime = 0.3 10 | image phone_click_effect: 11 | phone.asset("circle.png") 12 | alpha 0.34 matrixcolor TintMatrix("#464646") 13 | subpixel True xysize (25, 25) 14 | easein (phone_click_uptime * 0.4) xysize (50, 50) alpha 0.7 15 | easeout_quad (phone_click_uptime * 0.6) xysize (0, 0) alpha 0.0 16 | define phone_on_click_effect = ("phone_click_effect", phone_click_uptime) 17 | 18 | define phone_drag_uptime = 0.4 19 | image phone_drag_effect: 20 | phone.asset("circle.png") 21 | alpha 0.17 matrixcolor TintMatrix("#464646") 22 | subpixel True xysize (20, 20) 23 | easeout phone_drag_uptime alpha 0.0 xysize (0, 0) 24 | define phone_on_drag_effect = ("phone_drag_effect", phone_drag_uptime) 25 | 26 | define phone_on_release_effect = None 27 | 28 | init -100 python in phone.click_effects: 29 | import pygame_sdl2 as pygame 30 | # yes i know `SpriteManager`s exist :monikk: 31 | class ClickEffectDisplayable(object): 32 | def __init__(self, child, x, y, lifespan, last_st, zorder): 33 | self.child = child 34 | self.x = x 35 | self.y = y 36 | self.lifespan = lifespan 37 | self.last_st = last_st 38 | self.st = 0.0 39 | self.zorder = zorder 40 | 41 | @property 42 | def dead(self): 43 | return self.st >= self.lifespan 44 | 45 | class ClickEffects(renpy.Displayable, renpy.python.NoRollback): 46 | # zorders 47 | _CLICKED = 3 48 | _CLICK = 2 49 | _DRAG = 1 50 | 51 | def __init__(self, on_click, on_drag, on_release): 52 | super(ClickEffects, self).__init__() 53 | 54 | if on_click is None: 55 | self.on_click_d = self.on_click_lifespan = None 56 | else: 57 | on_click_d, on_click_lifespan = on_click 58 | self.on_click_lifespan = None if on_click_lifespan < 0.0 else on_click_lifespan 59 | self.on_click_d = renpy.displayable(on_click_d) 60 | 61 | if on_drag is None: 62 | self.on_drag_d = self.on_drag_lifespan = None 63 | else: 64 | on_drag_d, on_drag_lifespan = on_drag 65 | self.on_drag_lifespan = None if on_drag_lifespan < 0.0 else on_drag_lifespan 66 | self.on_drag_d = renpy.displayable(on_drag_d) 67 | 68 | if on_release is None: 69 | self.on_release_d = self.on_release_lifespan = None 70 | else: 71 | on_release_d, on_release_lifespan = on_release 72 | self.on_release_lifespan = None if on_release_lifespan < 0.0 else on_release_lifespan 73 | self.on_release_d = renpy.displayable(on_release_d) 74 | 75 | self._clicked = False 76 | self._dead_child = False 77 | self._needs_sort = False 78 | 79 | self.width = 0 80 | self.height = 0 81 | 82 | self.displayables = [ ] 83 | 84 | def render(self, w, h, st, at): 85 | self.width = w 86 | self.height = h 87 | 88 | rv = renpy.Render(w, h) 89 | rv.xclipping = True 90 | rv.yclipping = True 91 | 92 | if not self.displayables: return rv 93 | 94 | if self._dead_child: 95 | self.displayables[:] = [d for d in self.displayables if not d.dead] 96 | self._dead_child = False 97 | 98 | if self._needs_sort: # only sort when needed 99 | self.displayables.sort(key=lambda d: d.zorder) 100 | self._needs_sort = False 101 | 102 | for d in self.displayables: 103 | delta = st - d.last_st 104 | d.last_st = st 105 | d.st += delta 106 | self._dead_child |= d.dead 107 | 108 | cr = renpy.render(d.child, w, h, d.st, at) 109 | cr_w, cr_h = cr.get_size() 110 | 111 | rv.subpixel_blit(cr, (d.x - (cr_w / 2.0), d.y - (cr_h / 2.0)), main=False) 112 | 113 | renpy.redraw(self, 0.0) 114 | return rv 115 | 116 | def event(self, ev, x, y, st): 117 | # checking for mousewheel 118 | if getattr(ev, "button", None) in (4, 5): return None 119 | 120 | create_displayable = (0 <= x <= self.width and 0 <= y <= self.height) 121 | 122 | if ev.type in (pygame.MOUSEBUTTONDOWN, pygame.FINGERDOWN): 123 | self._clicked = True 124 | if create_displayable: self._create(self.on_click_d, x, y, self.on_click_lifespan, st, self._CLICK) 125 | 126 | elif ev.type in (pygame.MOUSEBUTTONUP, pygame.FINGERUP): 127 | self._clicked = False 128 | if create_displayable: self._create(self.on_release_d, x, y, self.on_release_lifespan, st, self._CLICKED) 129 | 130 | elif ev.type in (pygame.MOUSEMOTION, pygame.FINGERMOTION) and self._clicked: 131 | if create_displayable: self._create(self.on_drag_d, x, y, self.on_drag_lifespan, st, self._DRAG) 132 | 133 | return None 134 | 135 | def _create(self, d, x, y, lifespan, st, zorder): 136 | if d is None or lifespan is None: return 137 | 138 | if d._duplicatable: 139 | d = d._duplicate(None) 140 | d._unique() 141 | 142 | self.displayables.append(ClickEffectDisplayable(d, x, y, lifespan, st, zorder)) 143 | self._needs_sort = True 144 | renpy.redraw(self, 0.0) 145 | 146 | def visit(self): 147 | return list(set(d.child for d in self.displayables)) 148 | 149 | init 1500 python in phone.config: 150 | overlay_screens.append("_phone_click_effects") -------------------------------------------------------------------------------- /phone/system.rpy: -------------------------------------------------------------------------------- 1 | init offset = -120 2 | 3 | init python in phone.system: 4 | from renpy import store 5 | 6 | from pygame_sdl2.power import get_power_info 7 | def get_battery_level(): 8 | if battery_level is not None: return int(battery_level) 9 | return max(get_power_info().percent, 0) 10 | 11 | from socket import gethostbyname, gethostname 12 | CONNECTED = 1 13 | NO_INTERNET = 2 14 | NOT_CONNECTED = 3 15 | AIRPLANE_MODE = 4 16 | CELLULAR_DATA = 5 17 | 18 | renpy.const("phone.system.CONNECTED") 19 | renpy.const("phone.system.NO_INTERNET") 20 | renpy.const("phone.system.NOT_CONNECTED") 21 | renpy.const("phone.system.AIRPLANE_MODE") 22 | renpy.const("phone.system.CELLULAR_DATA") 23 | 24 | def get_internet_connection_state(): 25 | if airplane_mode: return AIRPLANE_MODE 26 | 27 | _wifi = wifi 28 | if _wifi is None: 29 | _wifi = gethostbyname(gethostname()) != "127.0.0.1" 30 | 31 | if not _wifi: 32 | if cellular_data: return CELLULAR_DATA 33 | return NOT_CONNECTED 34 | 35 | if not internet_connection: return NO_INTERNET 36 | return CONNECTED 37 | 38 | from datetime import datetime 39 | def get_date(): 40 | if date is not None: return date 41 | return datetime.now() 42 | 43 | # If any of these "If not `None`" values are `None`, they're taken from the player's device. 44 | default phone.system.date = None # If not `None`, a `datetime.datetime` object. 45 | default phone.system.battery_level = None # If not `None`, an integer. 46 | default phone.system.wifi = None # If not `None`, a boolean. 47 | 48 | # If true, some actions (notably in the status bar screen) won't do anything, preventing the player 49 | # from changing variables when they're not supposed to. 50 | default phone.system.locked = False 51 | 52 | default phone.system.airplane_mode = False 53 | default phone.system.bluetooth = False 54 | default phone.system.rotation_locked = False 55 | default phone.system.cellular_data = False 56 | default phone.system.internet_connection = True # Phone wifi can be on, yet no internet connection. 57 | default phone.system.at_list = [] # A transform or list of transforms applied to the phone screen (overlay screens excluded). 58 | default phone.system.dark_mode = False # `False` by default ew 59 | default phone.system.flashlight = False # should've named it "flashbang" smh 60 | 61 | # read only 62 | default phone.system.brightness = 1.0 # [phone.config.lowest_brightness, 1.0] --------------------------------------------------------------------------------