├── .editorconfig ├── .gitignore ├── ADVENTURE-DESIGN.md ├── EVENT-HANDERS.md ├── LICENSE ├── PORTING-CLASSIC-ADVENTURES.md ├── PORTING-EDX-ADVENTURES.md ├── Pipfile ├── Pipfile.lock ├── README.md ├── adventure ├── __init__.py ├── admin.py ├── api │ ├── __init__.py │ ├── designer │ │ ├── __init__.py │ │ ├── serializers.py │ │ └── views.py │ └── game │ │ ├── __init__.py │ │ ├── serializers.py │ │ └── views.py ├── apps.py ├── data │ ├── 001-the-beginners-cave.json │ ├── 002-lair-of-the-minotaur.json │ ├── 003-the-cave-of-the-mind.json │ ├── 008-abductors-quarters.json │ ├── 010-the-magic-kingdom.json │ ├── 013-the-caves-of-treasure-island.json │ ├── 014-furioso.json │ ├── 023-temple-of-ngurct.json │ ├── 026-assault-on-the-mole-man.json │ ├── 027-revenge-of-the-mole-man.json │ ├── 033-orb-of-polaris.json │ ├── 035-lair-of-mutants.json │ ├── 044-escape-from-the-orc-lair.json │ ├── 045-swordquest.json │ ├── 052-the-devils-dungeon.json │ ├── 057-manxome-foe.json │ ├── 069-black-castle-of-nagog.json │ ├── 077-temple-of-the-trolls.json │ ├── 078-princes-tavern.json │ ├── 107-last-dragon.json │ ├── 108-mines-of-moria.json │ ├── 109-forest-of-fear.json │ ├── 115-ring-of-doom.json │ ├── 140-beginners-forest.json │ ├── 194-attack-of-the-kretons.json │ ├── 195-the-training-ground.json │ ├── 206-curse-of-the-hellsblade.json │ ├── 213-demongate.json │ ├── 215-treasure-island.json │ ├── 216-pirates-cave.json │ ├── 230-well-of-the-great-ones.json │ ├── 245-draculas-chateau.json │ ├── 246-sword-of-inari.json │ ├── 252-cliffs-of-fire.json │ ├── 268-eamon-deluxe-50-demo-adventure.json │ ├── 273-stronghold-of-kahr-dur.json │ ├── 274-treachery-of-zorag.json │ ├── 275-clone-master.json │ └── 277-malleus-maleficarum.json ├── import_utils.py ├── management │ └── commands │ │ ├── dump_adventure.py │ │ ├── import.py │ │ ├── import_classic.py │ │ ├── import_classic7.py │ │ ├── import_hints.py │ │ └── import_json.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_auto_20160220_2256.py │ ├── 0003_auto_20160223_0003.py │ ├── 0004_auto_20160223_0044.py │ ├── 0005_auto_20160305_1457.py │ ├── 0006_effect_style.py │ ├── 0007_auto_20160306_0055.py │ ├── 0008_auto_20160320_2237.py │ ├── 0009_adventure_slug.py │ ├── 0010_auto_20160327_2227.py │ ├── 0011_auto_20160327_2346.py │ ├── 0012_adventure_edx_program_file.py │ ├── 0013_auto_20160403_0015.py │ ├── 0014_auto_20160419_2324.py │ ├── 0015_auto_20160503_2339.py │ ├── 0016_auto_20160504_0112.py │ ├── 0017_adventure_active.py │ ├── 0018_artifact_armor_type.py │ ├── 0019_artifact_clothing_type.py │ ├── 0020_auto_20160530_0036.py │ ├── 0021_artifact_hidden.py │ ├── 0023_auto_20160601_2350.py │ ├── 0024_hint_hintanswer.py │ ├── 0025_auto_20161029_2305.py │ ├── 0026_player_uuid.py │ ├── 0027_auto_20170114_1143.py │ ├── 0028_auto_20170114_1230.py │ ├── 0029_auto_20170114_1241.py │ ├── 0030_adventure_full_description.py │ ├── 0031_auto_20170119_2221.py │ ├── 0032_artifact_armor_penalty.py │ ├── 0033_playerartifact_value.py │ ├── 0034_adventure_dead_body_id.py │ ├── 0035_auto_20170206_0019.py │ ├── 0036_activitylog.py │ ├── 0037_auto_20170330_2232.py │ ├── 0038_auto_20170330_2246.py │ ├── 0039_auto_20170423_0043.py │ ├── 0040_auto_20170423_0052.py │ ├── 0041_auto_20170530_0035.py │ ├── 0042_activitylog_value.py │ ├── 0043_auto_20170813_1501.py │ ├── 0044_auto_20180124_2241.py │ ├── 0045_auto_20180127_1627.py │ ├── 0046_auto_20180128_0913.py │ ├── 0047_user.py │ ├── 0048_auto_20180304_1832.py │ ├── 0049_adventure_featured_month_squashed_0051_adventure_date_published.py │ ├── 0050_monster_special.py │ ├── 0051_hintanswer_spoiler.py │ ├── 0052_auto_20190215_2228.py │ ├── 0053_auto_20190217_2341.py │ ├── 0054_auto_20190412_2346.py │ ├── 0055_auto_20190522_2239.py │ ├── 0056_auto_20190526_2048.py │ ├── 0057_auto_20190526_2107.py │ ├── 0058_auto_20190703_2149.py │ ├── 0059_auto_20190706_1517.py │ ├── 0060_auto_20191002_0102.py │ ├── 0061_auto_20191213_0007.py │ ├── 0062_auto_20200501_0144.py │ ├── 0063_monster_combat_verbs.py │ ├── 0064_auto_20200529_0136.py │ ├── 0065_auto_20200529_1607.py │ ├── 0066_auto_20200726_2318.py │ ├── 0067_roomexit_hintanswer_adventure_id.py │ └── __init__.py ├── models.py ├── static │ ├── adventures │ │ ├── malleus-maleficarum │ │ │ └── virrat-map.jpg │ │ └── the-caves-of-treasure-island │ │ │ ├── Treasure-Island-map.jpg │ │ │ └── treasure-island-map.png │ ├── css │ │ └── bootstrap.min.css │ └── images │ │ ├── Eamon_dragon_NEUC.png │ │ ├── Eamon_dragon_facebook.png │ │ ├── favicon │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ └── site.webmanifest │ │ ├── parchment │ │ ├── center.png │ │ └── parchment-border.png │ │ ├── ravenmore │ │ └── 128 │ │ │ ├── Boots.png │ │ │ ├── armor.png │ │ │ ├── armor2.png │ │ │ ├── axe.png │ │ │ ├── axe2.png │ │ │ ├── axeDouble.png │ │ │ ├── axeDouble2.png │ │ │ ├── backpack.png │ │ │ ├── backpack_open.png │ │ │ ├── bow.png │ │ │ ├── bow2.png │ │ │ ├── bow_arrow_only.png │ │ │ ├── bow_bow_only.png │ │ │ ├── coin.png │ │ │ ├── dagger.png │ │ │ ├── dagger2.png │ │ │ ├── document.png │ │ │ ├── envelope.png │ │ │ ├── gem.png │ │ │ ├── gemBlue.png │ │ │ ├── gemGreen.png │ │ │ ├── gemRed.png │ │ │ ├── hammer.png │ │ │ ├── hammer2.png │ │ │ ├── heart.png │ │ │ ├── helmet.png │ │ │ ├── helmet2.png │ │ │ ├── leather.png │ │ │ ├── leather2.png │ │ │ ├── map - Copy.png │ │ │ ├── map.png │ │ │ ├── map_empty.png │ │ │ ├── necklace.png │ │ │ ├── potion.png │ │ │ ├── potion2.png │ │ │ ├── potion3.png │ │ │ ├── potion4.png │ │ │ ├── potionBlue.png │ │ │ ├── potionGreen.png │ │ │ ├── potionRed.png │ │ │ ├── potion_empty.png │ │ │ ├── ring.png │ │ │ ├── scroll.png │ │ │ ├── shield.png │ │ │ ├── shield2.png │ │ │ ├── shieldSmall.png │ │ │ ├── shieldSmall2.png │ │ │ ├── shield_semi.png │ │ │ ├── shield_wood.png │ │ │ ├── star.png │ │ │ ├── sword.png │ │ │ ├── sword2.png │ │ │ ├── swordWood.png │ │ │ ├── tome.png │ │ │ ├── tome_amber.png │ │ │ ├── tome_azure.png │ │ │ ├── tome_emerald.png │ │ │ ├── tools.png │ │ │ ├── tools_hammer.png │ │ │ ├── upg_spear.png │ │ │ ├── wand.png │ │ │ ├── wand2.png │ │ │ ├── woodSword.png │ │ │ └── x.png │ │ ├── sf_dustywall02.jpg │ │ └── sf_dustywall02_border.jpg ├── templates │ ├── _footer.html │ ├── _google_analytics.html │ ├── about.html │ ├── adventure-list.html │ ├── adventure.html │ ├── base.html │ ├── index.html │ ├── main-hall.html │ ├── manual.html │ └── privacy.html ├── tests.py ├── urls.py └── views.py ├── client ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── adventures │ ├── abductors-quarters │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── assault-on-the-mole-man │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── attack-of-the-kretons │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── base-adventure │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── beginners-forest │ │ ├── commands.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── black-castle-of-nagog │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── cliffs-of-fire │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── clone-master │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── curse-of-the-hellsblade │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── demo1 │ │ ├── commands.ts │ │ ├── event-handlers.ts │ │ ├── index.ts │ │ └── mock-data │ │ │ └── rooms.ts │ ├── demongate │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── draculas-chateau │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── eamon-deluxe-50-demo-adventure │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── escape-from-mt-moon │ │ ├── commands.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── escape-from-the-orc-lair │ │ ├── commands.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── forest-of-fear │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── furioso │ │ ├── commands.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── iron-prison │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── lair-of-mutants │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── lair-of-the-minotaur │ │ ├── commands.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── last-dragon │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── malleus-maleficarum │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── manxome-foe │ │ ├── commands.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── mines-of-moria │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── museum-of-unnatural-history │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── orb-of-polaris │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── pirates-cave │ │ ├── commands.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── princes-tavern │ │ ├── commands.spec.ts │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── quest-for-the-holy-grail │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── revenge-of-the-mole-man │ │ ├── commands.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── ring-of-doom │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── stronghold-of-kahr-dur │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── sword-of-inari │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── swordquest │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── temple-of-ngurct │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── temple-of-the-trolls │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── the-beginners-cave │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── the-cave-of-the-mind │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── the-caves-of-treasure-island │ │ ├── commands.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── the-devils-dungeon │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── the-magic-kingdom │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── the-training-ground │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ ├── treachery-of-zorag │ │ ├── commands.ts │ │ ├── custom-data.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ ├── functions.ts │ │ └── index.ts │ ├── treasure-island │ │ ├── commands.ts │ │ ├── event-handlers.ts │ │ └── index.ts │ └── well-of-the-great-ones │ │ ├── commands.ts │ │ ├── event-handlers.spec.ts │ │ ├── event-handlers.ts │ │ └── index.ts ├── babel.config.js ├── build │ └── static │ │ └── mock-data │ │ ├── adventure.json │ │ ├── artifacts.json │ │ ├── effects.json │ │ ├── monsters.json │ │ ├── player.json │ │ └── rooms.json ├── core │ ├── commands │ │ ├── base-command.ts │ │ ├── core-commands.ts │ │ ├── event-handler.ts │ │ └── optional-commands.ts │ ├── components │ │ ├── CommandList.tsx │ │ ├── CommandPrompt.tsx │ │ ├── Hints.tsx │ │ ├── History.tsx │ │ ├── HowToPlay.tsx │ │ ├── IntroText.tsx │ │ ├── MainProgram.tsx │ │ ├── Question.tsx │ │ ├── SamSlicker.tsx │ │ └── Status.tsx │ ├── index.tsx │ ├── models │ │ ├── artifact.spec.ts │ │ ├── artifact.ts │ │ ├── command-parser.ts │ │ ├── effect.ts │ │ ├── game-object.ts │ │ ├── game.spec.ts │ │ ├── game.ts │ │ ├── hint.ts │ │ ├── history-entry.spec.ts │ │ ├── history-entry.ts │ │ ├── history-manager.spec.ts │ │ ├── history-manager.ts │ │ ├── loadable.ts │ │ ├── modal.ts │ │ ├── monster.combat.spec.ts │ │ ├── monster.group.spec.ts │ │ ├── monster.spec.ts │ │ ├── monster.ts │ │ ├── operations-queue.ts │ │ ├── room.spec.ts │ │ └── room.ts │ ├── repositories │ │ ├── artifact-repo.spec.ts │ │ ├── artifact.repo.ts │ │ ├── effect.repo.ts │ │ ├── hint.repo.ts │ │ ├── monster-repo.spec.ts │ │ ├── monster.repo.ts │ │ └── room.repo.ts │ ├── types.ts │ └── utils │ │ ├── command.exception.ts │ │ ├── index.ts │ │ ├── logger.interface.ts │ │ ├── logger.ts │ │ ├── saved-game.interface.ts │ │ └── testing.ts ├── cypress.json ├── cypress │ ├── fixtures │ │ ├── adv1 │ │ │ ├── adventure.json │ │ │ ├── artifacts.json │ │ │ ├── effects.json │ │ │ ├── monsters.json │ │ │ ├── player.json │ │ │ └── rooms.json │ │ ├── adventures.json │ │ ├── character.json │ │ └── characters.json │ ├── integration │ │ ├── adventure-list.spec.js │ │ ├── adventure.spec.js │ │ ├── character-creation.spec.js │ │ ├── main-hall.spec.js │ │ └── shop.spec.js │ ├── plugins │ │ └── index.js │ └── support │ │ ├── commands.js │ │ ├── index.js │ │ └── page_objects │ │ ├── adventurePage.js │ │ ├── mainHallPage.js │ │ └── shopPage.js ├── designer │ ├── components │ │ ├── AdventureDetail.tsx │ │ ├── AdventureHeading.tsx │ │ ├── AdventureList.test.tsx │ │ ├── AdventureList.tsx │ │ ├── AdventureMainMenu.tsx │ │ ├── ArtifactDetail.tsx │ │ ├── ArtifactList.tsx │ │ ├── Designer.tsx │ │ ├── EffectDetail.tsx │ │ ├── EffectList.tsx │ │ ├── Login.tsx │ │ ├── MonsterDetail.tsx │ │ ├── MonsterList.tsx │ │ ├── RoomDetail.tsx │ │ ├── RoomList.tsx │ │ ├── common.test.tsx │ │ ├── common.tsx │ │ └── fields.tsx │ ├── constants.ts │ ├── contexts │ │ ├── adventure.tsx │ │ ├── form.ts │ │ └── user.ts │ ├── index.tsx │ ├── models │ │ ├── adventure.ts │ │ ├── artifact.ts │ │ ├── effect.ts │ │ ├── game-object.ts │ │ ├── hint.ts │ │ ├── loadable.ts │ │ ├── monster.ts │ │ └── room.ts │ ├── repositories │ │ ├── artifact.repo.ts │ │ ├── base.repo.ts │ │ ├── effect.repo.ts │ │ ├── hint.repo.ts │ │ ├── monster.repo.ts │ │ └── room.repo.ts │ ├── test-utils.tsx │ └── types.ts ├── jest.config.mjs ├── jest.setup.js ├── main-hall │ ├── components │ │ ├── AdventureList.tsx │ │ ├── Bank.tsx │ │ ├── MainHall.tsx │ │ ├── PlayerCreate.tsx │ │ ├── PlayerDetail.tsx │ │ ├── PlayerList.tsx │ │ ├── PlayerListItem.tsx │ │ ├── PlayerMenu.tsx │ │ ├── SavedGameTile.tsx │ │ ├── Shop │ │ │ ├── ArtifactTile.tsx │ │ │ ├── Shop.tsx │ │ │ └── shopItems.ts │ │ ├── Status.tsx │ │ ├── Witch │ │ │ ├── AttributeRow.tsx │ │ │ └── Witch.tsx │ │ └── Wizard │ │ │ ├── SpellListRow.tsx │ │ │ └── Wizard.tsx │ ├── hooks.ts │ ├── index.tsx │ ├── models │ │ ├── adventure.ts │ │ ├── artifact.ts │ │ ├── game-object.ts │ │ └── player.ts │ ├── registerServiceWorker.ts │ ├── store │ │ ├── index.ts │ │ └── player.ts │ ├── tests │ │ ├── MainHall.test.tsx │ │ └── Player.test.ts │ └── utils │ │ ├── api.ts │ │ ├── dice.ts │ │ └── index.ts ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json ├── scss │ └── style.scss ├── tsconfig.json ├── tsconfig.prod.json ├── tsconfig.test.json ├── tslint.json └── webpack.config.js ├── db ├── eamon.sqlite3.dist ├── post-import-fixes.sql ├── query magic wand type weapons.sql └── room exits for adventure.sql ├── designer ├── __init__.py ├── apps.py ├── templates │ └── designer.html ├── urls.py └── views.py ├── eamon ├── local_settings_example.py ├── settings.py ├── urls.py └── wsgi.py ├── fabfile.py ├── manage.py ├── news ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_auto_20170527_0125.py │ └── __init__.py ├── models.py ├── templates │ └── news.html ├── tests.py ├── urls.py └── views.py ├── player ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_savedgame_created.py │ ├── 0003_rating.py │ ├── 0004_player_playerartifact_playerprofile.py │ ├── 0005_move_player_data.py │ ├── 0006_alter_savedgame_player.py │ ├── 0007_playerprofile_slug.py │ ├── 0008_activitylog.py │ ├── 0009_move_activity_log.py │ ├── 0010_alter_savedgame_player.py │ └── __init__.py ├── models.py ├── serializers.py ├── urls.py └── views.py ├── sample_import ├── README.md ├── artifacts.json ├── effects.json ├── monsters.json └── rooms.json ├── static └── .gitkeep └── truncate.sql /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | # From the Django .editorconfig: https://github.com/django/django/blob/master/.editorconfig 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 4 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | end_of_line = lf 13 | charset = utf-8 14 | 15 | # Use 2 spaces for the HTML files 16 | [*.html] 17 | indent_size = 2 18 | 19 | # The JSON files contain newlines inconsistently 20 | [*.json] 21 | indent_size = 2 22 | insert_final_newline = ignore 23 | 24 | [**/admin/js/vendor/**] 25 | indent_style = ignore 26 | indent_size = ignore 27 | 28 | # Minified JavaScript files shouldn't be changed 29 | [**.min.js] 30 | indent_style = ignore 31 | insert_final_newline = ignore 32 | 33 | # Makefiles always use tabs for indentation 34 | [Makefile] 35 | indent_style = tab 36 | 37 | # Batch files use tabs for indentation 38 | [*.bat] 39 | indent_style = tab 40 | 41 | # Custom settings for CSS 42 | 43 | # Use 2 spaces for SCSS files 44 | [*.scss] 45 | indent_size = 2 46 | 47 | # Compiled CSS files shouldn't be changed 48 | [*.css] 49 | indent_style = ignore 50 | insert_final_newline = ignore 51 | 52 | # From the Angular2 .editorconfig: https://github.com/angular/angular/blob/master/.editorconfig 53 | 54 | # Use 2 spaces for TypeScript files 55 | [*.js] 56 | indent_size = 2 57 | [*.ts] 58 | indent_size = 2 59 | [*.tsx] 60 | indent_size = 2 61 | 62 | [*.md] 63 | insert_final_newline = false 64 | trim_trailing_whitespace = false 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /nbproject/ 2 | /static/node_modules/ 3 | /static/build/ 4 | /client/build/ 5 | **/**/*.js 6 | !/client/cypress/**/*.js 7 | !/client/*.js 8 | **/**/*.js.map 9 | **/__pycache__/ 10 | /.idea/ 11 | venv 12 | db/* 13 | eamon/local_settings.py 14 | static/* 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2017 Keith Dechant http://terranok.com 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | bleach = "~=3.2" 8 | chardet = "~=4.0" 9 | Django = "~=3.2.9" 10 | django-braces = "~=1.13" 11 | django-ckeditor = "~=6.1.0" 12 | django-cors-middleware = "~=1.5.0" 13 | django-debug-toolbar = "~=3.2.2" 14 | django-filter = "~=2.4" 15 | django-mptt = "~=0.12" 16 | django-rest-swagger = "~=2.2" 17 | django-settings-export = "==1.2.1" 18 | django-taggit = "~=1.3" 19 | django-taggit-serializer = "~=0.1" 20 | djangorestframework = "~=3.12.4" 21 | djangorestframework-simplejwt = "==4.8.0" 22 | "html5lib" = "==1.1" 23 | fabric = "~=3.2.2" 24 | regex = "~=2024.11.6" 25 | requests = "~=2.26.0" 26 | requests-oauthlib = "~=1.3.0" 27 | setuptools = "*" 28 | six = "~=1.17.0" 29 | sqlparse = "~=0.4.2" 30 | PyYAML = "~=6.0.2" 31 | 32 | [dev-packages] 33 | 34 | [pipenv] 35 | allow_prereleases = true 36 | -------------------------------------------------------------------------------- /adventure/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/__init__.py -------------------------------------------------------------------------------- /adventure/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/api/__init__.py -------------------------------------------------------------------------------- /adventure/api/designer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/api/designer/__init__.py -------------------------------------------------------------------------------- /adventure/api/game/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/api/game/__init__.py -------------------------------------------------------------------------------- /adventure/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AdventureConfig(AppConfig): 5 | name = 'adventure' 6 | -------------------------------------------------------------------------------- /adventure/import_utils.py: -------------------------------------------------------------------------------- 1 | import regex 2 | 3 | 4 | def sentence_case(string): 5 | """ 6 | Converts a string to sentence case. 7 | From http://stackoverflow.com/questions/39969202/convert-uppercase-string-to-sentence-case-in-python 8 | Args: 9 | string: The input string 10 | 11 | Returns: 12 | The string, now in sentence case 13 | """ 14 | return '. '.join(i.capitalize() for i in string.split('. ')) 15 | 16 | 17 | def fix_40char_text(text): 18 | return sentence_case(regex.sub(r'\s{2,}', " ", text)) 19 | -------------------------------------------------------------------------------- /adventure/migrations/0002_auto_20160220_2256.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.1 on 2016-02-21 06:56 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='artifact', 17 | name='is_worn', 18 | field=models.BooleanField(default=False), 19 | ), 20 | migrations.AddField( 21 | model_name='monster', 22 | name='count', 23 | field=models.IntegerField(default=1), 24 | ), 25 | migrations.AddField( 26 | model_name='monster', 27 | name='original_group_size', 28 | field=models.IntegerField(default=1), 29 | ), 30 | migrations.AlterField( 31 | model_name='monster', 32 | name='room_id', 33 | field=models.IntegerField(null=True), 34 | ), 35 | ] 36 | -------------------------------------------------------------------------------- /adventure/migrations/0004_auto_20160223_0044.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.1 on 2016-02-23 08:44 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0003_auto_20160223_0003'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='adventure', 17 | name='edx', 18 | field=models.CharField(max_length=50, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0005_auto_20160305_1457.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-03-05 22:57 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0004_auto_20160223_0044'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='adventure', 17 | name='directions', 18 | field=models.IntegerField(default=6), 19 | ), 20 | migrations.AddField( 21 | model_name='adventure', 22 | name='edx_version', 23 | field=models.FloatField(blank=True, default=0, null=True), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /adventure/migrations/0006_effect_style.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-03-06 08:02 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0005_auto_20160305_1457'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='effect', 17 | name='style', 18 | field=models.TextField(max_length=20, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0008_auto_20160320_2237.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-03-21 05:37 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0007_auto_20160306_0055'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RenameField( 16 | model_name='roomexit', 17 | old_name='key_id', 18 | new_name='door_id', 19 | ), 20 | migrations.AddField( 21 | model_name='artifact', 22 | name='key_id', 23 | field=models.IntegerField(help_text='If a container or door, the artifact ID of the key that opens it', null=True), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /adventure/migrations/0009_adventure_slug.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-03-24 06:15 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0008_auto_20160320_2237'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='adventure', 17 | name='slug', 18 | field=models.SlugField(null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0010_auto_20160327_2227.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-03-28 05:27 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0009_adventure_slug'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='artifact', 17 | name='guard_id', 18 | field=models.IntegerField(help_text='If a bound monster, the ID of a monster that prevents the player from freeing it', null=True), 19 | ), 20 | migrations.AlterField( 21 | model_name='artifact', 22 | name='key_id', 23 | field=models.IntegerField(help_text='If a container, door, or bound monster, the artifact ID of the key that opens it', null=True), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /adventure/migrations/0011_auto_20160327_2346.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-03-28 06:46 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0010_auto_20160327_2227'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='artifact', 17 | name='effect_id', 18 | field=models.IntegerField(help_text='First effect ID for Readable artifacts', null=True), 19 | ), 20 | migrations.AddField( 21 | model_name='artifact', 22 | name='num_effects', 23 | field=models.IntegerField(help_text='Number of effects for Readable artifacts (legacy)', null=True), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /adventure/migrations/0012_adventure_edx_program_file.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-04-03 04:11 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0011_auto_20160327_2346'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='adventure', 17 | name='edx_program_file', 18 | field=models.CharField(max_length=50, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0013_auto_20160403_0015.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-04-03 07:15 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0012_adventure_edx_program_file'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='artifact', 17 | name='synonyms', 18 | field=models.CharField(max_length=255, null=True), 19 | ), 20 | migrations.AddField( 21 | model_name='monster', 22 | name='synonyms', 23 | field=models.CharField(max_length=255, null=True), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /adventure/migrations/0014_auto_20160419_2324.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-04-20 06:24 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0013_auto_20160403_0015'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='playerartifact', 17 | name='hands', 18 | field=models.IntegerField(choices=[(1, 'One-handed'), (2, 'Two-handed')], default=1), 19 | ), 20 | migrations.AddField( 21 | model_name='playerartifact', 22 | name='weight', 23 | field=models.IntegerField(default=0), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /adventure/migrations/0015_auto_20160503_2339.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.5 on 2016-05-04 06:39 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0014_auto_20160419_2324'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='player', 17 | name='gender', 18 | field=models.CharField(choices=[('m', 'Male'), ('f', 'Female')], max_length=6), 19 | ), 20 | migrations.AlterField( 21 | model_name='playerartifact', 22 | name='dice', 23 | field=models.IntegerField(default=1, null=True), 24 | ), 25 | migrations.AlterField( 26 | model_name='playerartifact', 27 | name='odds', 28 | field=models.IntegerField(default=0, null=True), 29 | ), 30 | migrations.AlterField( 31 | model_name='playerartifact', 32 | name='sides', 33 | field=models.IntegerField(default=1, null=True), 34 | ), 35 | migrations.AlterField( 36 | model_name='playerartifact', 37 | name='weapon_type', 38 | field=models.IntegerField(choices=[(1, 'Axe'), (2, 'Bow'), (3, 'Club'), (4, 'Spear'), (5, 'Sword')], default=0, null=True), 39 | ), 40 | ] 41 | -------------------------------------------------------------------------------- /adventure/migrations/0016_auto_20160504_0112.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.5 on 2016-05-04 08:12 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0015_auto_20160503_2339'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RenameField( 16 | model_name='playerartifact', 17 | old_name='odds', 18 | new_name='weapon_odds', 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0017_adventure_active.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.5 on 2016-05-08 07:41 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0016_auto_20160504_0112'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='adventure', 17 | name='active', 18 | field=models.BooleanField(default=0), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0018_artifact_armor_type.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.6 on 2016-05-30 03:42 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0017_adventure_active'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='artifact', 17 | name='armor_type', 18 | field=models.IntegerField(choices=[(0, 'Armor'), (1, 'Shield')], null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0019_artifact_clothing_type.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.6 on 2016-05-30 04:33 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0018_artifact_armor_type'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='artifact', 17 | name='clothing_type', 18 | field=models.IntegerField(choices=[(0, 'Clothes or Armor/Shield'), (1, 'Coats, Capes, etc.'), (2, 'Shoes, boots'), (3, 'Gloves'), (4, 'Hats, headwear'), (5, 'Jewelry'), (6, 'Undergarments')], null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0020_auto_20160530_0036.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.6 on 2016-05-30 07:36 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0019_artifact_clothing_type'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='playerartifact', 17 | name='armor_class', 18 | field=models.IntegerField(default=0, null=True), 19 | ), 20 | migrations.AlterField( 21 | model_name='playerartifact', 22 | name='armor_penalty', 23 | field=models.IntegerField(default=0, null=True), 24 | ), 25 | migrations.AlterField( 26 | model_name='playerartifact', 27 | name='armor_type', 28 | field=models.IntegerField(choices=[(0, 'Armor'), (1, 'Shield')], default=0, null=True), 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /adventure/migrations/0021_artifact_hidden.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.6 on 2016-05-30 08:11 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0020_auto_20160530_0036'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='artifact', 17 | name='hidden', 18 | field=models.BooleanField(default=False), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0023_auto_20160601_2350.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.6 on 2016-06-02 06:50 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0021_artifact_hidden'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='artifact', 17 | name='hardiness', 18 | field=models.IntegerField(help_text='If a door or container that must be smashed open, how much damage does it take to open it?', null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0024_hint_hintanswer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.2 on 2016-10-29 06:13 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('adventure', '0023_auto_20160601_2350'), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='Hint', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('index', models.IntegerField(null=True)), 21 | ('edx', models.CharField(max_length=50, null=True)), 22 | ('question', models.CharField(max_length=255)), 23 | ('adventure', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='hints', to='adventure.Adventure')), 24 | ], 25 | ), 26 | migrations.CreateModel( 27 | name='HintAnswer', 28 | fields=[ 29 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 30 | ('index', models.IntegerField(null=True)), 31 | ('answer', models.TextField(max_length=1000)), 32 | ('hint', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers', to='adventure.Hint')), 33 | ], 34 | ), 35 | ] 36 | -------------------------------------------------------------------------------- /adventure/migrations/0025_auto_20161029_2305.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.2 on 2016-10-30 06:05 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0024_hint_hintanswer'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='adventure', 17 | name='first_hint', 18 | field=models.IntegerField(null=True), 19 | ), 20 | migrations.AddField( 21 | model_name='adventure', 22 | name='last_hint', 23 | field=models.IntegerField(null=True), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /adventure/migrations/0026_player_uuid.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2016-11-05 07:49 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0025_auto_20161029_2305'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='player', 17 | name='uuid', 18 | field=models.CharField(max_length=255, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0027_auto_20170114_1143.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2017-01-14 19:43 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import taggit.managers 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('taggit', '0002_auto_20150616_2121'), 13 | ('adventure', '0026_player_uuid'), 14 | ] 15 | 16 | operations = [ 17 | migrations.AddField( 18 | model_name='adventure', 19 | name='intro_text', 20 | field=models.TextField(null=True), 21 | ), 22 | migrations.AddField( 23 | model_name='adventure', 24 | name='tags', 25 | field=taggit.managers.TaggableManager(help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags'), 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /adventure/migrations/0028_auto_20170114_1230.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2017-01-14 20:30 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import taggit.managers 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('adventure', '0027_auto_20170114_1143'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AlterModelOptions( 17 | name='adventure', 18 | options={'ordering': ['name']}, 19 | ), 20 | migrations.AlterField( 21 | model_name='adventure', 22 | name='description', 23 | field=models.TextField(blank=True, null=True), 24 | ), 25 | migrations.AlterField( 26 | model_name='adventure', 27 | name='intro_text', 28 | field=models.TextField(blank=True, null=True), 29 | ), 30 | migrations.AlterField( 31 | model_name='adventure', 32 | name='tags', 33 | field=taggit.managers.TaggableManager(blank=True, help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags'), 34 | ), 35 | ] 36 | -------------------------------------------------------------------------------- /adventure/migrations/0029_auto_20170114_1241.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2017-01-14 20:41 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0028_auto_20170114_1230'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='adventure', 17 | name='description', 18 | field=models.TextField(blank=True, default=''), 19 | ), 20 | migrations.AlterField( 21 | model_name='adventure', 22 | name='intro_text', 23 | field=models.TextField(blank=True, default=''), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /adventure/migrations/0030_adventure_full_description.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2017-01-14 21:38 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0029_auto_20170114_1241'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='adventure', 17 | name='full_description', 18 | field=models.TextField(blank=True, default=''), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0031_auto_20170119_2221.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2017-01-20 06:21 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0030_adventure_full_description'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='adventure', 17 | name='intro_question', 18 | field=models.TextField(blank=True, default='', help_text='If you want to ask the adventurer a question when they start the adventure, put the question text here. The answer will be available in the game object.'), 19 | ), 20 | migrations.AlterField( 21 | model_name='adventure', 22 | name='intro_text', 23 | field=models.TextField(blank=True, default='', help_text='Text shown to the adventurer when they begin the adventure. Use this to set up the story.'), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /adventure/migrations/0032_artifact_armor_penalty.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2017-01-24 08:47 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0031_auto_20170119_2221'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='artifact', 17 | name='armor_penalty', 18 | field=models.IntegerField(default=0, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0033_playerartifact_value.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2017-01-31 07:08 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0032_artifact_armor_penalty'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='playerartifact', 17 | name='value', 18 | field=models.IntegerField(default=0), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0034_adventure_dead_body_id.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2017-02-02 06:28 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0033_playerartifact_value'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='adventure', 17 | name='dead_body_id', 18 | field=models.IntegerField(blank=True, default=0, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0035_auto_20170206_0019.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2017-02-06 08:19 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0034_adventure_dead_body_id'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='adventure', 17 | name='dead_body_id', 18 | field=models.IntegerField(blank=True, default=0, help_text='The artifact ID of the first dead body. Leave blank to not use dead body artifacts.', null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0036_activitylog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2017-03-23 05:26 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('adventure', '0035_auto_20170206_0019'), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='ActivityLog', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('type', models.CharField(max_length=255)), 21 | ('created', models.DateTimeField(auto_now_add=True, null=True)), 22 | ('adventure', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='activity_log', to='adventure.Adventure')), 23 | ('player', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='activity_log', to='adventure.Player')), 24 | ], 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /adventure/migrations/0037_auto_20170330_2232.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2017-03-31 05:32 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0036_activitylog'), 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Author', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('name', models.CharField(max_length=50)), 20 | ], 21 | ), 22 | migrations.AddField( 23 | model_name='adventure', 24 | name='authors', 25 | field=models.ManyToManyField(to='adventure.Author'), 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /adventure/migrations/0038_auto_20170330_2246.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.3 on 2017-03-31 05:46 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0037_auto_20170330_2232'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='adventure', 17 | name='first_hint', 18 | field=models.IntegerField(blank=True, null=True), 19 | ), 20 | migrations.AlterField( 21 | model_name='adventure', 22 | name='last_hint', 23 | field=models.IntegerField(blank=True, null=True), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /adventure/migrations/0040_auto_20170423_0052.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2017-04-23 07:52 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0039_auto_20170423_0043'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='artifact', 17 | name='armor_class', 18 | field=models.IntegerField(default=0, help_text='(Armor only) How many hits does this armor protect against?'), 19 | ), 20 | migrations.AlterField( 21 | model_name='artifact', 22 | name='armor_penalty', 23 | field=models.IntegerField(default=0, help_text='(Armor only) How much armor expertise does the player need to use this armor without penalty?', null=True), 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /adventure/migrations/0042_activitylog_value.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2017-06-06 04:50 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('adventure', '0041_auto_20170530_0035'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='activitylog', 17 | name='value', 18 | field=models.IntegerField(blank=True, null=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /adventure/migrations/0044_auto_20180124_2241.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0 on 2018-01-25 06:41 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0043_auto_20170813_1501'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='artifact', 15 | name='linked_door_id', 16 | field=models.IntegerField(blank=True, help_text='To make a two-sided door, enter the artifact ID of the other side of the door. They will open and close as a set.', null=True), 17 | ), 18 | migrations.AddField( 19 | model_name='monster', 20 | name='container_id', 21 | field=models.IntegerField(blank=True, help_text='Container artifact where this monster starts. The monster will enter the room as soon as the container is opened. e.g., a vampire who awakes when you open his coffin', null=True), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /adventure/migrations/0046_auto_20180128_0913.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0 on 2018-01-28 17:13 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('adventure', '0045_auto_20180127_1627'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='activitylog', 16 | name='player', 17 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='activity_log', to='adventure.Player'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /adventure/migrations/0047_user.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0.2 on 2018-02-13 07:38 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0046_auto_20180128_0913'), 10 | ] 11 | 12 | operations = [ 13 | migrations.CreateModel( 14 | name='User', 15 | fields=[ 16 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 17 | ('social_id', models.CharField(max_length=100, null=True)), 18 | ('uuid', models.CharField(max_length=255, null=True)), 19 | ], 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /adventure/migrations/0048_auto_20180304_1832.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0.2 on 2018-03-05 02:32 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0047_user'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RenameModel( 14 | old_name='User', 15 | new_name='PlayerProfile', 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /adventure/migrations/0049_adventure_featured_month_squashed_0051_adventure_date_published.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0.2 on 2018-07-04 07:33 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0048_auto_20180304_1832'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='adventure', 15 | name='featured_month', 16 | field=models.CharField(blank=True, max_length=7, null=True), 17 | ), 18 | migrations.AddField( 19 | model_name='adventure', 20 | name='date_published', 21 | field=models.DateField(blank=True, null=True), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /adventure/migrations/0050_monster_special.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.1 on 2019-01-19 09:45 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0049_adventure_featured_month_squashed_0051_adventure_date_published'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='monster', 15 | name='special', 16 | field=models.CharField(blank=True, max_length=255, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /adventure/migrations/0051_hintanswer_spoiler.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.1 on 2019-02-16 06:26 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0050_monster_special'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='hintanswer', 15 | name='spoiler', 16 | field=models.BooleanField(default=False, help_text='Obscure the answer until the user shows it.'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /adventure/migrations/0052_auto_20190215_2228.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.1 on 2019-02-16 06:28 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0051_hintanswer_spoiler'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='hint', 15 | name='edx', 16 | field=models.CharField(blank=True, max_length=50, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /adventure/migrations/0053_auto_20190217_2341.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.1 on 2019-02-18 07:41 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0052_auto_20190215_2228'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='artifact', 15 | name='armor_class', 16 | field=models.IntegerField(default=0, help_text='(Armor only) How many hits does this armor protect against?', null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /adventure/migrations/0054_auto_20190412_2346.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.7 on 2019-04-13 06:46 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0053_auto_20190217_2341'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='monster', 15 | name='original_group_size', 16 | ), 17 | migrations.AddField( 18 | model_name='monster', 19 | name='name_plural', 20 | field=models.CharField(blank=True, help_text='The plural form of the name. Used only with group monsters.', max_length=255, null=True), 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /adventure/migrations/0055_auto_20190522_2239.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.1 on 2019-05-23 05:39 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0054_auto_20190412_2346'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='adventure', 15 | name='intro_text', 16 | field=models.TextField(blank=True, default='', help_text='Text shown to the adventurer when they begin the adventure. Use this to set up the story. Split it into multiple pages by using a line containing three hyphens as a break. Supports Markdown.'), 17 | ), 18 | migrations.AlterField( 19 | model_name='artifact', 20 | name='description', 21 | field=models.TextField(help_text='Supports Markdown.', max_length=1000), 22 | ), 23 | migrations.AlterField( 24 | model_name='effect', 25 | name='text', 26 | field=models.TextField(help_text='Supports Markdown.', max_length=65535), 27 | ), 28 | migrations.AlterField( 29 | model_name='hintanswer', 30 | name='answer', 31 | field=models.TextField(help_text='Supports Markdown.', max_length=1000), 32 | ), 33 | migrations.AlterField( 34 | model_name='monster', 35 | name='description', 36 | field=models.TextField(help_text='Supports Markdown.', max_length=1000), 37 | ), 38 | ] 39 | -------------------------------------------------------------------------------- /adventure/migrations/0057_auto_20190526_2107.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.1 on 2019-05-27 04:07 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0056_auto_20190526_2048'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='artifact', 15 | name='is_markdown', 16 | field=models.BooleanField(choices=[(False, 'Plain text'), (True, 'Markdown')], default=0, verbose_name='Text format'), 17 | ), 18 | migrations.AlterField( 19 | model_name='effect', 20 | name='is_markdown', 21 | field=models.BooleanField(choices=[(False, 'Plain text'), (True, 'Markdown')], default=0, verbose_name='Text format'), 22 | ), 23 | migrations.AlterField( 24 | model_name='monster', 25 | name='is_markdown', 26 | field=models.BooleanField(choices=[(False, 'Plain text'), (True, 'Markdown')], default=0, verbose_name='Text format'), 27 | ), 28 | migrations.AlterField( 29 | model_name='room', 30 | name='is_markdown', 31 | field=models.BooleanField(choices=[(False, 'Plain text'), (True, 'Markdown')], default=0, verbose_name='Text format'), 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /adventure/migrations/0058_auto_20190703_2149.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.1 on 2019-07-04 04:49 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0057_auto_20190526_2107'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='monster', 15 | name='defense_bonus', 16 | field=models.IntegerField(default=0, help_text='Gives the monster an additional percent bonus to avoid being hit. (Rare)'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /adventure/migrations/0059_auto_20190706_1517.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.1 on 2019-07-06 22:17 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0058_auto_20190703_2149'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='artifact', 15 | name='article', 16 | field=models.CharField(blank=True, help_text="Optional article or adjective that appears before the name, e.g., 'a', 'the', 'some'.", max_length=20, null=True), 17 | ), 18 | migrations.AddField( 19 | model_name='monster', 20 | name='article', 21 | field=models.CharField(blank=True, help_text="Optional article or adjective that appears before the name, e.g., 'a', 'the', 'some'. Does not apply to group monsters.", max_length=20, null=True), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /adventure/migrations/0060_auto_20191002_0102.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.5 on 2019-10-02 08:02 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0059_auto_20190706_1517'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='roomexit', 15 | name='message', 16 | ), 17 | migrations.AddField( 18 | model_name='room', 19 | name='dark_description', 20 | field=models.TextField(blank=True, help_text="The description shown if the room is dark and the player doesn't have a light. Leave blank to use the standard 'it's too dark to see' message.", max_length=1000, null=True), 21 | ), 22 | migrations.AddField( 23 | model_name='room', 24 | name='dark_name', 25 | field=models.CharField(blank=True, help_text="The name shown if the room is dark and the player doesn't have a light. Leave blank to use the standard 'in the dark' message.", max_length=255, null=True), 26 | ), 27 | migrations.AddField( 28 | model_name='roomexit', 29 | name='effect_id', 30 | field=models.IntegerField(blank=True, help_text="The effect will be shown when the player moves in this direction. You can also enter a zero for the connection and an effect ID to set up a custom message on a non-existent exit, e.g., if the player can't go in the ocean without a boat, etc.", null=True), 31 | ), 32 | ] 33 | -------------------------------------------------------------------------------- /adventure/migrations/0061_auto_20191213_0007.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.7 on 2019-12-13 08:07 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0060_auto_20191002_0102'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='artifact', 15 | name='armor_type', 16 | field=models.IntegerField(blank=True, choices=[(0, 'Armor'), (1, 'Shield'), (2, 'Helmet')], null=True), 17 | ), 18 | migrations.AlterField( 19 | model_name='playerartifact', 20 | name='armor_type', 21 | field=models.IntegerField(choices=[(0, 'Armor'), (1, 'Shield'), (2, 'Helmet')], default=0, null=True), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /adventure/migrations/0062_auto_20200501_0144.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.5 on 2020-05-01 08:44 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0061_auto_20191213_0007'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='artifact', 15 | name='armor_type', 16 | field=models.IntegerField(blank=True, choices=[(0, 'Armor'), (1, 'Shield'), (2, 'Helmet'), (3, 'Gloves'), (4, 'Ring')], null=True), 17 | ), 18 | migrations.AlterField( 19 | model_name='effect', 20 | name='style', 21 | field=models.CharField(blank=True, choices=[('', 'Normal'), ('emphasis', 'Bold'), ('success', 'Success (green)'), ('special', 'Special 1 (blue)'), ('special2', 'Special 1 (purple)'), ('warning', 'Warning (orange)'), ('danger', 'Danger (red)')], max_length=20, null=True), 22 | ), 23 | migrations.AlterField( 24 | model_name='playerartifact', 25 | name='armor_type', 26 | field=models.IntegerField(choices=[(0, 'Armor'), (1, 'Shield'), (2, 'Helmet'), (3, 'Gloves'), (4, 'Ring')], default=0, null=True), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /adventure/migrations/0063_monster_combat_verbs.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.5 on 2020-05-29 08:27 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0062_auto_20200501_0144'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='monster', 15 | name='combat_verbs', 16 | field=models.CharField(blank=True, max_length=255, help_text="Custom combat verbs for this monster, e.g., 'stings' or 'breathes fire at'. Leave blank to use the standard verbs.", null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /adventure/migrations/0064_auto_20200529_0136.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.5 on 2020-05-29 08:36 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0063_monster_combat_verbs'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='monster', 15 | name='gender', 16 | field=models.CharField(blank=True, choices=[('male', 'Male'), ('female', 'Female'), ('none', 'None')], max_length=6, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /adventure/migrations/0065_auto_20200529_1607.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.5 on 2020-05-29 23:07 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0064_auto_20200529_0136'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='artifact', 15 | name='data', 16 | field=models.TextField(blank=True, help_text='Adventure-specific data for this artifact, e.g., elemental weapon, etc.Enter as a JSON object.', max_length=1000, null=True), 17 | ), 18 | migrations.AddField( 19 | model_name='monster', 20 | name='data', 21 | field=models.TextField(blank=True, help_text='Adventure-specific data for this monster, e.g., type of monster like vampire, undead, soldier, frost, etc. Data can be used in custom code. Enter as a JSON object.', max_length=1000, null=True), 22 | ), 23 | migrations.AddField( 24 | model_name='room', 25 | name='data', 26 | field=models.TextField(blank=True, help_text='Adventure-specific data for this room, e.g., room type or environment (road, cave, snow, etc.). Data can be used in custom code. Enter as a JSON object.', max_length=1000, null=True), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /adventure/migrations/0066_auto_20200726_2318.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.5 on 2020-07-27 06:18 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('adventure', '0065_auto_20200529_1607'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='artifact', 15 | name='guard_id', 16 | field=models.IntegerField(blank=True, help_text='If a bound monster, the ID of a monster that prevents the player from freeing it. For other artifact types, the ID of a monster that prevents the player from picking it up.', null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /adventure/migrations/0067_roomexit_hintanswer_adventure_id.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.4 on 2021-07-28 08:39 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('adventure', '0066_auto_20200726_2318'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='hintanswer', 16 | name='adventure', 17 | field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='hint_answers', to='adventure.adventure'), 18 | ), 19 | migrations.AddField( 20 | model_name='roomexit', 21 | name='adventure', 22 | field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='room_exits', to='adventure.adventure'), 23 | ), 24 | # populate the fields added above 25 | migrations.RunSQL("update adventure_roomexit" 26 | " set adventure_id =" 27 | " (select adventure_id " 28 | " from adventure_room" 29 | " where adventure_room.id = adventure_roomexit.room_from_id)"), 30 | migrations.RunSQL("update adventure_hintanswer" 31 | " set adventure_id =" 32 | " (select adventure_id" 33 | " from adventure_hint" 34 | " where adventure_hint.id = adventure_hintanswer.hint_id)"), 35 | ] 36 | -------------------------------------------------------------------------------- /adventure/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/migrations/__init__.py -------------------------------------------------------------------------------- /adventure/static/adventures/malleus-maleficarum/virrat-map.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/adventures/malleus-maleficarum/virrat-map.jpg -------------------------------------------------------------------------------- /adventure/static/adventures/the-caves-of-treasure-island/Treasure-Island-map.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/adventures/the-caves-of-treasure-island/Treasure-Island-map.jpg -------------------------------------------------------------------------------- /adventure/static/adventures/the-caves-of-treasure-island/treasure-island-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/adventures/the-caves-of-treasure-island/treasure-island-map.png -------------------------------------------------------------------------------- /adventure/static/images/Eamon_dragon_NEUC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/Eamon_dragon_NEUC.png -------------------------------------------------------------------------------- /adventure/static/images/Eamon_dragon_facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/Eamon_dragon_facebook.png -------------------------------------------------------------------------------- /adventure/static/images/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /adventure/static/images/favicon/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/favicon/android-chrome-512x512.png -------------------------------------------------------------------------------- /adventure/static/images/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /adventure/static/images/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /adventure/static/images/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /adventure/static/images/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/favicon/favicon.ico -------------------------------------------------------------------------------- /adventure/static/images/favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /adventure/static/images/parchment/center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/parchment/center.png -------------------------------------------------------------------------------- /adventure/static/images/parchment/parchment-border.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/parchment/parchment-border.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/Boots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/Boots.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/armor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/armor.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/armor2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/armor2.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/axe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/axe.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/axe2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/axe2.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/axeDouble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/axeDouble.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/axeDouble2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/axeDouble2.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/backpack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/backpack.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/backpack_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/backpack_open.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/bow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/bow.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/bow2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/bow2.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/bow_arrow_only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/bow_arrow_only.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/bow_bow_only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/bow_bow_only.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/coin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/coin.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/dagger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/dagger.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/dagger2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/dagger2.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/document.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/document.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/envelope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/envelope.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/gem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/gem.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/gemBlue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/gemBlue.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/gemGreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/gemGreen.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/gemRed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/gemRed.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/hammer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/hammer.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/hammer2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/hammer2.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/heart.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/helmet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/helmet.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/helmet2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/helmet2.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/leather.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/leather.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/leather2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/leather2.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/map - Copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/map - Copy.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/map.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/map_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/map_empty.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/necklace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/necklace.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/potion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/potion.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/potion2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/potion2.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/potion3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/potion3.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/potion4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/potion4.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/potionBlue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/potionBlue.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/potionGreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/potionGreen.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/potionRed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/potionRed.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/potion_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/potion_empty.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/ring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/ring.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/scroll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/scroll.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/shield.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/shield.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/shield2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/shield2.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/shieldSmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/shieldSmall.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/shieldSmall2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/shieldSmall2.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/shield_semi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/shield_semi.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/shield_wood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/shield_wood.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/star.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/sword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/sword.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/sword2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/sword2.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/swordWood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/swordWood.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/tome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/tome.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/tome_amber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/tome_amber.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/tome_azure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/tome_azure.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/tome_emerald.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/tome_emerald.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/tools.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/tools_hammer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/tools_hammer.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/upg_spear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/upg_spear.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/wand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/wand.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/wand2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/wand2.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/woodSword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/woodSword.png -------------------------------------------------------------------------------- /adventure/static/images/ravenmore/128/x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/ravenmore/128/x.png -------------------------------------------------------------------------------- /adventure/static/images/sf_dustywall02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/sf_dustywall02.jpg -------------------------------------------------------------------------------- /adventure/static/images/sf_dustywall02_border.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/adventure/static/images/sf_dustywall02_border.jpg -------------------------------------------------------------------------------- /adventure/templates/_footer.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 13 |
14 |
15 |
16 | Privacy Policy 17 |
18 |
19 | Icons by Ravenmore 20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /adventure/templates/_google_analytics.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /adventure/templates/adventure.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load static %} 3 | 4 | {% block title %}{% endblock %} 5 | 6 | {% block heading %} 7 | {% endblock %} 8 | 9 | {% block content %} 10 | 11 |
12 | 13 | {% endblock %} 14 | 15 | {% block endscripts %} 16 | {% with adventure_root="adventures/" %} 17 | 18 | 19 | 33 | 34 | 35 | {% endwith %} 36 | {% endblock %} 37 | 38 | -------------------------------------------------------------------------------- /adventure/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load static %} 3 | 4 | {% block title %}Adventure List{% endblock %} 5 | 6 | {% block content %} 7 | 8 |
9 |
10 |
11 |
12 |
13 |

Welcome to EAMON!

14 |

Eamon is a computerized fantasy role-playing system. Create one character and go on dozens of different adventures!

15 |

16 |
17 |
18 | The Eamon Dragon 19 |
20 |
21 |

Based on the Eamon Adventure Series, written by Donald Brown for the Apple ][, and on Eamon Deluxe by Frank Black.

22 |
23 |
24 |
25 |
26 |
27 | 28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /adventure/templates/main-hall.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load static %} 3 | 4 | {% block title %}Main Hall{% endblock %} 5 | 6 | {% block scripts %} 7 | 8 | 9 | {% endblock %} 10 | 11 | {% block content %} 12 | 13 |
Welcome to the Wonderful World of Eamon...
14 | 15 | 16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /adventure/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | from .models import Adventure 4 | 5 | 6 | def index(request, path=''): 7 | """ 8 | The home page 9 | """ 10 | return render(request, 'index.html') 11 | 12 | 13 | def about(request): 14 | """ 15 | The "about" page 16 | """ 17 | return render(request, 'about.html') 18 | 19 | 20 | def privacy_policy(request): 21 | """ 22 | The "privacy policy" page 23 | """ 24 | return render(request, 'privacy.html') 25 | 26 | 27 | def main_hall(request): 28 | """ 29 | The container for the "main hall" react app 30 | """ 31 | return render(request, 'main-hall.html') 32 | 33 | 34 | def adventure(request, slug): 35 | """ 36 | The container for the "core" a.k.a. "adventure" angular app 37 | """ 38 | return render(request, 'adventure.html', {'slug': slug}) 39 | 40 | 41 | def adventure_list(request): 42 | adventures = Adventure.objects.filter(active=True).order_by('name') 43 | return render(request, 'adventure-list.html', {'adventures': adventures}) 44 | 45 | 46 | def manual(request): 47 | return render(request, 'manual.html') 48 | -------------------------------------------------------------------------------- /client/.eslintignore: -------------------------------------------------------------------------------- 1 | .eslintrc.js 2 | build 3 | node_modules 4 | webpack.config.js 5 | -------------------------------------------------------------------------------- /client/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | env: { 5 | browser: true, 6 | node: true, 7 | es2021: true, 8 | "cypress/globals": true 9 | }, 10 | plugins: [ 11 | '@typescript-eslint', 12 | 'cypress' 13 | ], 14 | extends: [ 15 | 'eslint:recommended', 16 | 'plugin:@typescript-eslint/recommended', 17 | ], 18 | rules: { 19 | 'no-prototype-builtins': 'off', 20 | 'no-case-declarations': 'off', 21 | '@typescript-eslint/ban-ts-comment': 'off', 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /client/adventures/abductors-quarters/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | export var custom_commands = []; 6 | 7 | // add your custom commands here 8 | -------------------------------------------------------------------------------- /client/adventures/abductors-quarters/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/assault-on-the-mole-man/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {CommandException} from "../../core/utils/command.exception"; 3 | 4 | declare let game: Game; 5 | 6 | export var custom_commands = []; 7 | 8 | custom_commands.push({ 9 | name: "push", 10 | verbs: ["push", "hit"], 11 | description: "Used for pushing buttons on machinery.", 12 | examples: ['PUSH BUTTON', 'HIT BUTTON'], 13 | run: function(verb: string, arg: string): void { 14 | // this command is really just an alias for the "use" command 15 | const artifact = game.artifacts.getLocalByName(arg); 16 | if (artifact) { 17 | if ([8,9,14,15].indexOf(artifact.id) !== -1) { 18 | // buttons. "push x" is just a synonym for "use x" 19 | artifact.use(); 20 | } else { 21 | game.history.write("Nothing happens."); 22 | } 23 | } else { 24 | throw new CommandException("You don't have it and it's not here."); 25 | } 26 | }, 27 | }); 28 | 29 | -------------------------------------------------------------------------------- /client/adventures/assault-on-the-mole-man/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/attack-of-the-kretons/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/base-adventure/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | // The "game" object contains the event handlers and custom commands defined for the loaded adventure. 6 | declare const game: Game; 7 | 8 | export const custom_commands = []; 9 | 10 | // add your custom commands here 11 | -------------------------------------------------------------------------------- /client/adventures/base-adventure/event-handlers.spec.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Unit tests for {base adventure} 3 | */ 4 | import Game from "../../core/models/game"; 5 | import {Monster} from "../../core/models/monster"; 6 | import {Artifact} from "../../core/models/artifact"; 7 | import {initLiveGame, expectEffectSeen, expectEffectNotSeen, playerAttackMock, movePlayer} from "../../core/utils/testing"; 8 | import {event_handlers} from "./event-handlers"; 9 | import {custom_commands} from "./commands"; 10 | 11 | // SETUP 12 | 13 | const game = new Game(); 14 | 15 | beforeAll(() => { global['game'] = game; }); 16 | afterAll(() => { delete global['game']; }); 17 | 18 | // to initialize the test, we need to load the whole game data. 19 | // this requires that a real, live API is running. 20 | beforeEach(() => { 21 | game.registerAdventureLogic(event_handlers, custom_commands); 22 | game.slug = '{put your adventure slug here}'; 23 | return initLiveGame(game); 24 | }); 25 | 26 | // uncomment the following for debugging 27 | // afterEach(() => { game.history.history.map((h) => console.log(h.command, h.results)); }); 28 | 29 | // TESTS 30 | 31 | test("effect 1", () => { 32 | // do some game actions and write assertions here 33 | 34 | // for example: 35 | expect(game.rooms.get(1)).not.toBeNull(); 36 | 37 | }); 38 | 39 | test("effect 2", () => { 40 | // do some game actions and write assertions here 41 | 42 | // for example: 43 | expect(game.rooms.get(1)).not.toBeNull(); 44 | 45 | }); 46 | -------------------------------------------------------------------------------- /client/adventures/base-adventure/event-handlers.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Artifact} from "../../core/models/artifact"; 3 | import {Monster} from "../../core/models/monster"; 4 | import {RoomExit} from "../../core/models/room"; 5 | import {Room} from "../../core/models/room"; 6 | 7 | // The "game" object contains the event handlers and custom commands defined for the loaded adventure. 8 | declare const game: Game; 9 | 10 | export const event_handlers = { 11 | 12 | "start": function(): void { 13 | // add your custom game start code here 14 | }, 15 | 16 | // add your custom event handlers here 17 | 18 | // every adventure should have a "power" event handler. 19 | // 'power' event handler takes a 1d100 dice roll as an argument. 20 | // this event handler only runs if the spell was successful. 21 | "power": function(roll: number): void { 22 | if (roll <= 50) { 23 | game.history.write("You hear a loud sonic boom which echoes all around you!"); 24 | } else if (roll <= 75) { 25 | // teleport to random room 26 | game.history.write("You are being teleported..."); 27 | const room = game.rooms.getRandom(); 28 | game.player.moveToRoom(room.id); 29 | game.skip_battle_actions = true; 30 | } else { 31 | game.history.write("All your wounds are healed!"); 32 | game.player.heal(1000); 33 | } 34 | }, 35 | 36 | }; // end event handlers 37 | 38 | 39 | // declare any functions used by event handlers and custom commands 40 | -------------------------------------------------------------------------------- /client/adventures/base-adventure/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/beginners-forest/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | 4 | export var custom_commands = []; 5 | 6 | // add your custom commands here 7 | -------------------------------------------------------------------------------- /client/adventures/beginners-forest/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/black-castle-of-nagog/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | export var custom_commands = []; 6 | 7 | // add your custom commands here 8 | -------------------------------------------------------------------------------- /client/adventures/black-castle-of-nagog/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/cliffs-of-fire/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | declare let game: Game; 6 | 7 | export var custom_commands = []; 8 | 9 | custom_commands.push({ 10 | name: "wave", 11 | verbs: ["wave"], 12 | description: "Waves something in the air.", 13 | examples: ['WAVE WAND'], 14 | run: function(verb: string, arg: string): void { 15 | // this command is really just a wrapper around the "use" command 16 | const artifact = game.artifacts.getLocalByName(arg); 17 | if (artifact) { 18 | if (artifact.id === 3) { 19 | // black wand. "wave x" is just a synonym for "use x" 20 | artifact.use(); 21 | } else { 22 | throw new CommandException("Nothing happens."); 23 | } 24 | } else { 25 | throw new CommandException("Nothing happens."); 26 | } 27 | }, 28 | }); 29 | -------------------------------------------------------------------------------- /client/adventures/cliffs-of-fire/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/clone-master/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | export var custom_commands = []; 6 | 7 | // add your custom commands here 8 | -------------------------------------------------------------------------------- /client/adventures/clone-master/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/curse-of-the-hellsblade/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | 4 | export var custom_commands = []; 5 | -------------------------------------------------------------------------------- /client/adventures/curse-of-the-hellsblade/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/demo1/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | 3 | declare let game: Game; 4 | 5 | export var custom_commands = []; 6 | 7 | custom_commands.push({ 8 | name: 'trollsfire', 9 | verbs: ['trollsfire'], 10 | run: function(verb, arg) { 11 | game.history.write('As you say the magic word (Trollsfire), green flames rise from the sword\'s blade'); 12 | } 13 | }); 14 | 15 | custom_commands.push({ 16 | name: 'go', 17 | verbs: ['go'], 18 | run: function(verb, arg) { 19 | const exits = game.rooms.current_room.exits; 20 | const rand = exits[Math.floor(Math.random() * exits.length)]; 21 | game.command_parser.run(rand.direction, false); 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /client/adventures/demo1/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/demongate/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | export var custom_commands = []; 6 | 7 | // add your custom commands here 8 | -------------------------------------------------------------------------------- /client/adventures/demongate/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/draculas-chateau/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | declare let game: Game; 6 | 7 | export var custom_commands = []; 8 | 9 | custom_commands.push({ 10 | name: "dig", 11 | verbs: ["dig"], 12 | description: "Digs a hole.", 13 | examples: ['DIG'], 14 | run: function(verb: string, arg: string): void { 15 | if (game.artifacts.get(65).isHere()) { 16 | // shovel. "dig" is just a synonym for "use shovel" 17 | game.artifacts.get(65).use(); 18 | } else { 19 | throw new CommandException("You don't have anything to dig with."); 20 | } 21 | 22 | }, 23 | }); 24 | 25 | -------------------------------------------------------------------------------- /client/adventures/draculas-chateau/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/eamon-deluxe-50-demo-adventure/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | 4 | export var custom_commands = []; 5 | 6 | // add your custom commands here 7 | -------------------------------------------------------------------------------- /client/adventures/eamon-deluxe-50-demo-adventure/event-handlers.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | 3 | declare let game: Game; 4 | 5 | export var event_handlers = { 6 | 7 | // NOTE: This adventure has no special event handlers (except POWER). 8 | // This adventure is meant as a test of the core logic. 9 | 10 | // every adventure should have a "power" event handler. 11 | // 'power' event handler takes a 1d100 dice roll as an argument 12 | "power": function(roll) { 13 | if (roll <= 50) { 14 | game.history.write("You hear a loud sonic boom which echoes all around you!"); 15 | } else if (roll <= 75) { 16 | game.history.write('A fortune cookie appears in mid-air and explodes! The smoking paper left behind reads, "YOU SUDDENLY FIND YOU CANNOT CARRY ALL OF THE ITEMS YOU ARE CARRYING, AND THEY FALL TO THE GROUND." How strange...'); 17 | } else { 18 | game.history.write('A fortune cookie appears in mid-air and explodes! The smoking paper left behind reads, "THE SECTION OF THE TUNNEL YOU ARE IN COLLAPSES AND YOU DIE." How strange...'); 19 | } 20 | }, 21 | 22 | }; // end event handlers 23 | -------------------------------------------------------------------------------- /client/adventures/eamon-deluxe-50-demo-adventure/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/escape-from-mt-moon/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | // The "game" object contains the event handlers and custom commands defined for the loaded adventure. 6 | declare const game: Game; 7 | 8 | export const custom_commands = []; 9 | 10 | // add your custom commands here 11 | -------------------------------------------------------------------------------- /client/adventures/escape-from-mt-moon/event-handlers.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Artifact} from "../../core/models/artifact"; 3 | import {Monster} from "../../core/models/monster"; 4 | import {RoomExit} from "../../core/models/room"; 5 | import {Room} from "../../core/models/room"; 6 | 7 | // The "game" object contains the event handlers and custom commands defined for the loaded adventure. 8 | declare const game: Game; 9 | 10 | export const event_handlers = { 11 | 12 | "start": function(): void { 13 | // add your custom game start code here 14 | }, 15 | 16 | // add your custom event handlers here 17 | 18 | // every adventure should have a "power" event handler. 19 | // 'power' event handler takes a 1d100 dice roll as an argument. 20 | // this event handler only runs if the spell was successful. 21 | "power": function(roll: number): void { 22 | if (roll <= 50) { 23 | game.history.write("You hear a loud sonic boom which echoes all around you!"); 24 | } else if (roll <= 75) { 25 | // teleport to random room 26 | game.history.write("You are being teleported..."); 27 | const room = game.rooms.getRandom(); 28 | game.player.moveToRoom(room.id); 29 | game.skip_battle_actions = true; 30 | } else { 31 | game.history.write("All your wounds are healed!"); 32 | game.player.heal(1000); 33 | } 34 | }, 35 | 36 | }; // end event handlers 37 | 38 | 39 | // declare any functions used by event handlers and custom commands 40 | -------------------------------------------------------------------------------- /client/adventures/escape-from-mt-moon/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | 9 | -------------------------------------------------------------------------------- /client/adventures/escape-from-the-orc-lair/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | 4 | export var custom_commands = []; 5 | 6 | // add your custom commands here 7 | -------------------------------------------------------------------------------- /client/adventures/escape-from-the-orc-lair/event-handlers.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Artifact} from "../../core/models/artifact"; 3 | import {Monster} from "../../core/models/monster"; 4 | import {RoomExit} from "../../core/models/room"; 5 | import {Room} from "../../core/models/room"; 6 | 7 | // NOTE: nothing special here. This adventure runs on the base code. 8 | declare let game: Game; 9 | 10 | export var event_handlers = { 11 | 12 | // every adventure should have a "power" event handler. 13 | // 'power' event handler takes a 1d100 dice roll as an argument. 14 | // this event handler only runs if the spell was successful. 15 | "power": function(roll) { 16 | game.history.write("You hear a loud sonic boom which echoes all around you!"); 17 | }, 18 | 19 | }; // end event handlers 20 | -------------------------------------------------------------------------------- /client/adventures/escape-from-the-orc-lair/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/forest-of-fear/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | // The "game" object contains the event handlers and custom commands defined for the loaded adventure. 6 | declare const game: Game; 7 | 8 | export const custom_commands = []; 9 | 10 | // add your custom commands here 11 | -------------------------------------------------------------------------------- /client/adventures/forest-of-fear/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/furioso/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | 4 | export var custom_commands = []; 5 | 6 | // add your custom commands here 7 | -------------------------------------------------------------------------------- /client/adventures/furioso/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/iron-prison/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | // The "game" object contains the event handlers and custom commands defined for the loaded adventure. 6 | declare const game: Game; 7 | 8 | export const custom_commands = []; 9 | 10 | // add your custom commands here 11 | -------------------------------------------------------------------------------- /client/adventures/iron-prison/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/lair-of-mutants/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/lair-of-the-minotaur/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | declare let game: Game; 6 | 7 | export var custom_commands = []; 8 | 9 | custom_commands.push({ 10 | name: "dig", 11 | verbs: ["dig"], 12 | description: "Digs a hole.", 13 | examples: ['DIG'], 14 | run: function(verb: string, arg: string): void { 15 | if (game.artifacts.get(9).isHere()) { 16 | // shovel. "dig" is just a synonym for "use shovel" 17 | game.artifacts.get(9).use(); 18 | } else { 19 | throw new CommandException("You don't have anything to dig with."); 20 | } 21 | 22 | }, 23 | }); 24 | 25 | -------------------------------------------------------------------------------- /client/adventures/lair-of-the-minotaur/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/last-dragon/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | export var custom_commands = []; 6 | 7 | // add your custom commands here 8 | -------------------------------------------------------------------------------- /client/adventures/last-dragon/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/malleus-maleficarum/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/manxome-foe/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | // The "game" object contains the event handlers and custom commands defined for the loaded adventure. 6 | declare let game; 7 | 8 | export var custom_commands = []; 9 | 10 | // add your custom commands here 11 | -------------------------------------------------------------------------------- /client/adventures/manxome-foe/event-handlers.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Artifact} from "../../core/models/artifact"; 3 | import {Monster} from "../../core/models/monster"; 4 | import {RoomExit} from "../../core/models/room"; 5 | import {Room} from "../../core/models/room"; 6 | 7 | // The "game" object contains the event handlers and custom commands defined for the loaded adventure. 8 | declare let game; 9 | 10 | export var event_handlers = { 11 | 12 | "seeMonster": function (monster: Monster): void { 13 | // tweedledee/tweedledum share a description, as do the raths 14 | if (monster.id === 4 || monster.id === 17) { 15 | game.history.suppressNextMessage = true; 16 | } 17 | }, 18 | 19 | // every adventure should have a "power" event handler. 20 | // 'power' event handler takes a 1d100 dice roll as an argument. 21 | // this event handler only runs if the spell was successful. 22 | "power": function(roll) { 23 | if (roll <= 50) { 24 | game.history.write("You hear a loud sonic boom which echoes all around you!"); 25 | } else if (roll <= 75) { 26 | // teleport to random room 27 | game.history.write("You are being teleported..."); 28 | const room = game.rooms.getRandom(); 29 | game.player.moveToRoom(room.id); 30 | game.skip_battle_actions = true; 31 | } else { 32 | game.history.write("All your wounds are healed!"); 33 | game.player.heal(1000); 34 | } 35 | }, 36 | 37 | }; // end event handlers 38 | -------------------------------------------------------------------------------- /client/adventures/manxome-foe/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/mines-of-moria/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | // The "game" object contains the event handlers and custom commands defined for the loaded adventure. 6 | declare let game: Game; 7 | 8 | export var custom_commands = []; 9 | 10 | // add your custom commands here 11 | -------------------------------------------------------------------------------- /client/adventures/mines-of-moria/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/museum-of-unnatural-history/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | 3 | // The "game" object contains the event handlers and custom commands defined for the loaded adventure. 4 | declare const game: Game; 5 | 6 | export const custom_commands = []; 7 | 8 | custom_commands.push({ 9 | name: "assemble", 10 | verbs: ["assemble"], 11 | description: "Puts something together. You'll need the required components first.", 12 | examples: ['ASSEMBLE something'], 13 | run: function(verb: string, arg: string): void { 14 | arg = arg.toLowerCase(); 15 | 16 | if (arg === 'powder' || arg === 'gunpowder') { 17 | if (game.artifacts.allAreHere([1, 7, 19])) { 18 | game.effects.print(12); 19 | game.artifacts.get(35).moveToRoom(); 20 | } else { 21 | game.effects.print(14); 22 | } 23 | } 24 | 25 | if (arg === 'bomb' || arg === 'device') { 26 | if (game.data.made_bomb) { 27 | game.history.write('You already did!'); 28 | return; 29 | } 30 | if (game.artifacts.allAreHere([14, 16, 35])) { 31 | game.effects.print(13); 32 | game.artifacts.get(14).destroy(); 33 | game.artifacts.get(16).destroy(); 34 | game.artifacts.get(35).destroy(); 35 | game.artifacts.get(34).moveToRoom(); 36 | game.data.made_bomb = true; 37 | } else { 38 | game.effects.print(15); 39 | } 40 | } 41 | }, 42 | }); 43 | -------------------------------------------------------------------------------- /client/adventures/museum-of-unnatural-history/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/orb-of-polaris/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | export var custom_commands = []; 6 | 7 | // add your custom commands here 8 | -------------------------------------------------------------------------------- /client/adventures/orb-of-polaris/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/pirates-cave/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | export var custom_commands = []; 6 | 7 | // this file intentionally left blank 8 | -------------------------------------------------------------------------------- /client/adventures/pirates-cave/event-handlers.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | 3 | declare let game: Game; 4 | 5 | export var event_handlers = { 6 | 7 | "start": function() { 8 | game.exit_message = 'You return to the main hall.'; 9 | }, 10 | 11 | // every adventure should have a "power" event handler. 12 | // 'power' event handler takes a 1d100 dice roll as an argument. 13 | // this event handler only runs if the spell was successful. 14 | "power": function(roll) { 15 | if (roll <= 50) { 16 | game.history.write("You hear a loud sonic boom which echoes all around you!"); 17 | } else if (roll <= 75) { 18 | // teleport to random room 19 | game.history.write("You are being teleported..."); 20 | const room = game.rooms.getRandom(); 21 | game.player.moveToRoom(room.id); 22 | game.skip_battle_actions = true; 23 | } else { 24 | game.history.write("All your wounds are healed!"); 25 | game.player.heal(1000); 26 | } 27 | }, 28 | 29 | }; // end event handlers 30 | -------------------------------------------------------------------------------- /client/adventures/pirates-cave/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/princes-tavern/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/quest-for-the-holy-grail/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/revenge-of-the-mole-man/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | export var custom_commands = []; 6 | 7 | // add your custom commands here 8 | -------------------------------------------------------------------------------- /client/adventures/revenge-of-the-mole-man/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/ring-of-doom/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | // The "game" object contains the event handlers and custom commands defined for the loaded adventure. 6 | declare const game: Game; 7 | 8 | export const custom_commands = []; 9 | 10 | // add your custom commands here 11 | -------------------------------------------------------------------------------- /client/adventures/ring-of-doom/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/stronghold-of-kahr-dur/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | export var custom_commands = []; 6 | 7 | // add your custom commands here 8 | -------------------------------------------------------------------------------- /client/adventures/stronghold-of-kahr-dur/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/sword-of-inari/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/swordquest/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | export var custom_commands = []; 6 | 7 | // add your custom commands here 8 | -------------------------------------------------------------------------------- /client/adventures/swordquest/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/temple-of-ngurct/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | export var custom_commands = []; 6 | 7 | // add your custom commands here 8 | -------------------------------------------------------------------------------- /client/adventures/temple-of-ngurct/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/temple-of-the-trolls/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/the-beginners-cave/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {light_trollsfire, put_out_trollsfire} from "./event-handlers"; 3 | 4 | declare let game: Game; 5 | 6 | export var custom_commands = []; 7 | 8 | custom_commands.push({ 9 | name: "trollsfire", 10 | verbs: ["trollsfire"], 11 | description: "Activates a special item.", 12 | examples: ['TROLLSFIRE or SAY TROLLSFIRE'], 13 | run: function(verb: string, arg: string): void { 14 | const trollsfire = game.artifacts.get(10); 15 | 16 | if (game.player.hasArtifact(trollsfire.id)) { 17 | if (!trollsfire.is_lit) { 18 | game.effects.print(4, "success"); 19 | if (game.player.weapon_id === trollsfire.id) { 20 | // player has trollsfire ready. increase its stats. 21 | light_trollsfire(); 22 | } else { 23 | // turned on when carrying but not ready. Ouch. 24 | game.effects.print(5, "warning"); 25 | game.player.injure(game.diceRoll(1, 5), true); 26 | } 27 | } else { 28 | game.effects.print(6, "success"); 29 | put_out_trollsfire(); 30 | } 31 | } else { 32 | game.history.write("Nothing happens."); 33 | } 34 | }, 35 | }); 36 | -------------------------------------------------------------------------------- /client/adventures/the-beginners-cave/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/the-cave-of-the-mind/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | declare let game: Game; 6 | 7 | export var custom_commands = []; 8 | 9 | custom_commands.push({ 10 | name: "play", 11 | verbs: ["play"], 12 | run: function(verb: string, arg: string): void { 13 | // this command is really just a wrapper around the "use" command 14 | const artifact = game.artifacts.getLocalByName(arg); 15 | if (artifact) { 16 | if (artifact.id === 21) { 17 | // harmonica. "play x" is just a synonym for "use x" 18 | artifact.use(); 19 | } else { 20 | throw new CommandException("You can't play that."); 21 | } 22 | } else { 23 | throw new CommandException("You don't have it and it's not here."); 24 | } 25 | 26 | }, 27 | }); 28 | -------------------------------------------------------------------------------- /client/adventures/the-cave-of-the-mind/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/the-caves-of-treasure-island/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | declare let game: Game; 6 | 7 | export var custom_commands = []; 8 | 9 | custom_commands.push({ 10 | name: "dig", 11 | verbs: ["dig"], 12 | description: "Digs a hole.", 13 | examples: ['DIG'], 14 | run: function(verb: string, arg: string): void { 15 | if (game.artifacts.get(3).isHere()) { 16 | // shovel. "dig" is just a synonym for "use shovel" 17 | game.artifacts.get(3).use(); 18 | } else { 19 | throw new CommandException("You don't have anything to dig with."); 20 | } 21 | 22 | }, 23 | }); 24 | 25 | custom_commands.push({ 26 | name: "play", 27 | verbs: ["play"], 28 | description: "Plays a musical instrument.", 29 | examples: ['PLAY GUITAR'], 30 | run: function(verb: string, arg: string): void { 31 | // this command is really just a wrapper around the "use" command 32 | const artifact = game.artifacts.getLocalByName(arg); 33 | if (artifact) { 34 | if (artifact.id === 18 || artifact.id === 31) { 35 | // magic harp or flute. "play x" is just a synonym for "use x" 36 | artifact.use(); 37 | } else { 38 | throw new CommandException("You can't play that."); 39 | } 40 | } else { 41 | throw new CommandException("You don't have it and it's not here."); 42 | } 43 | }, 44 | }); 45 | -------------------------------------------------------------------------------- /client/adventures/the-caves-of-treasure-island/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/the-devils-dungeon/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/the-magic-kingdom/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | 4 | export var custom_commands = []; 5 | 6 | // add your custom commands here 7 | -------------------------------------------------------------------------------- /client/adventures/the-magic-kingdom/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/the-training-ground/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {CommandException} from "../../core/utils/command.exception"; 3 | 4 | declare let game: Game; 5 | 6 | export var custom_commands = []; 7 | 8 | custom_commands.push({ 9 | name: "buy", 10 | verbs: ["buy"], 11 | description: "Buys an item from a merchant. Items that are for sale will be listed in the game window.", 12 | examples: ['BUY POTION'], 13 | run: function(verb: string, arg: string): void { 14 | arg = arg.toLowerCase(); 15 | const for_sale_here = game.artifacts.all.filter(a => a.data.for_sale && a.monster_id && game.monsters.get(a.monster_id).isHere()); 16 | const artifact = for_sale_here.find(a => a.match(arg)); 17 | if (!artifact) { 18 | throw new CommandException("No one here has that for sale."); 19 | } 20 | if (artifact.value > game.player.gold) { 21 | throw new CommandException(`That costs ${artifact.value} gold pieces and you only have ${game.player.gold}.`); 22 | } 23 | 24 | game.modal.confirm(`That costs ${artifact.value} gold pieces. Do you want to buy it?`, answer => { 25 | if (answer === 'Yes') { 26 | game.history.write(`You buy the ${artifact.name}.`); 27 | artifact.showDescription(); 28 | artifact.moveToInventory(); 29 | game.player.gold -= artifact.value; 30 | game.player.updateInventory(); 31 | artifact.data.for_sale = false; 32 | } else { 33 | game.history.write(`"Maybe next time."`); 34 | } 35 | }); 36 | } 37 | }); 38 | 39 | -------------------------------------------------------------------------------- /client/adventures/the-training-ground/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/treachery-of-zorag/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/treasure-island/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | export var custom_commands = []; 6 | 7 | // this file intentionally left blank 8 | -------------------------------------------------------------------------------- /client/adventures/treasure-island/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/adventures/well-of-the-great-ones/commands.ts: -------------------------------------------------------------------------------- 1 | import Game from "../../core/models/game"; 2 | import {Monster} from "../../core/models/monster"; 3 | import {CommandException} from "../../core/utils/command.exception"; 4 | 5 | // The "game" object contains the event handlers and custom commands defined for the loaded adventure. 6 | declare let game; 7 | 8 | export var custom_commands = []; 9 | 10 | // add your custom commands here 11 | -------------------------------------------------------------------------------- /client/adventures/well-of-the-great-ones/index.ts: -------------------------------------------------------------------------------- 1 | // This file is the entry script for Webpack's ts-loader. Do not edit this file. 2 | import Game from '../../core/models/game'; 3 | import { custom_commands } from './commands'; 4 | import { event_handlers } from './event-handlers'; 5 | 6 | export const game = new Game(); 7 | game.registerAdventureLogic(event_handlers, custom_commands); 8 | -------------------------------------------------------------------------------- /client/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['@babel/preset-env', {targets: {node: 'current'}}], 4 | '@babel/preset-react', 5 | '@babel/preset-typescript', 6 | ], 7 | }; 8 | -------------------------------------------------------------------------------- /client/build/static/mock-data/adventure.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 0, 3 | "name": "Demo adventure", 4 | "description": "Welcome to the demo! This is a simple adventure used for development and automated tests. You will be exploring a small castle.", 5 | "intro_text": "" 6 | } 7 | -------------------------------------------------------------------------------- /client/build/static/mock-data/effects.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /client/core/commands/base-command.ts: -------------------------------------------------------------------------------- 1 | import Game from "../models/game"; 2 | 3 | /** 4 | * Interface BaseCommand. 5 | * Interface for commands a player can give. 6 | */ 7 | export interface BaseCommand { 8 | name: string; 9 | verbs: string[]; 10 | category?: string; 11 | description?: string; 12 | examples?: string[]; 13 | secret?: boolean; 14 | /** 15 | * Optional function to change what appears in the history window. 16 | * @param verb 17 | */ 18 | history_display? (verb: string); 19 | 20 | /** 21 | * The main function that contains the command logic 22 | * @param verb 23 | * @param arg 24 | */ 25 | run(verb, arg); 26 | } 27 | 28 | /** 29 | * Class CustomCommand. 30 | * A class used to define custom commands 31 | */ 32 | export class CustomCommand implements BaseCommand { 33 | name: string; 34 | verbs: string[]; 35 | category?: string; 36 | description?: string; 37 | examples?: string[]; 38 | game: Game; 39 | run(verb: string, arg: string) { } 40 | } 41 | -------------------------------------------------------------------------------- /client/core/commands/event-handler.ts: -------------------------------------------------------------------------------- 1 | import Game from "../models/game"; 2 | import {Artifact} from "../models/artifact"; 3 | import {Monster} from "../models/monster"; 4 | 5 | /** 6 | * EventHandler class. 7 | * A class used to define a game event handler. This allows custom logic to 8 | * be defined in an adventure. 9 | * 10 | * When a game event is triggered during execution (usually during a command), 11 | * the game searches for a matching EventHandler and calls its run() method. 12 | * 13 | * The EventHandler objects should be instantiated in an adventure's "event-handlers" file. 14 | */ 15 | export default class EventHandler { 16 | name: string; 17 | game: Game; 18 | run(arg1: number | string | Artifact | Monster, arg2?: Artifact | Monster, arg3?: Artifact | Monster) { } 19 | } 20 | -------------------------------------------------------------------------------- /client/core/index.tsx: -------------------------------------------------------------------------------- 1 | // polyfills for IE 11 2 | import "core-js/stable"; 3 | import "regenerator-runtime/runtime"; 4 | 5 | import * as React from 'react'; 6 | import * as ReactDOM from 'react-dom'; 7 | import MainProgram from './components/MainProgram'; 8 | // import registerServiceWorker from './registerServiceWorker'; 9 | 10 | ReactDOM.render( 11 | , 12 | document.getElementById('root') as HTMLElement 13 | ); 14 | // registerServiceWorker(); 15 | -------------------------------------------------------------------------------- /client/core/models/effect.ts: -------------------------------------------------------------------------------- 1 | import {GameObject} from "./game-object"; 2 | 3 | /** 4 | * Effect class. Represents special effect text that can be displayed 5 | * by scripts during game play. 6 | */ 7 | export class Effect extends GameObject { 8 | 9 | id: number; 10 | text: string; 11 | style: string; 12 | next: number; // another effect chained onto this one 13 | next_inline: number; // a chained effect that is printed without a paragraph break 14 | replacements: object; // strings that will be replaced within the effect text 15 | } 16 | -------------------------------------------------------------------------------- /client/core/models/game.spec.ts: -------------------------------------------------------------------------------- 1 | import Game from "./game"; 2 | 3 | const game = new Game(); 4 | 5 | describe("Game class", function() { 6 | 7 | test("should roll some dice", () => { 8 | let roll: number; 9 | // using sides = 1 to avoid having to worry about random numbers 10 | expect(game.diceRoll(1, 1)).toBe(1); 11 | expect(game.diceRoll(3, 1)).toBe(3); 12 | // edge cases 13 | expect(game.diceRoll(1, 0)).toBe(0); 14 | expect(game.diceRoll(3, -1)).toBe(-3); 15 | // test some random numbers 16 | for (let i = 0; i < 20; i++) { 17 | roll = game.diceRoll(1, 5); 18 | expect(roll).toBeGreaterThan(0); 19 | expect(roll).toBeLessThan(6); 20 | roll = game.diceRoll(1, -5); 21 | expect(roll).toBeGreaterThan(-6); 22 | expect(roll).toBeLessThan(0); 23 | } 24 | 25 | // test the mock random numbers feature 26 | game.mock_random_numbers = [42, 5, 99]; 27 | expect(game.diceRoll(1, 100)).toBe(42); 28 | expect(game.diceRoll(1, 100)).toBe(5); 29 | expect(game.diceRoll(1, 100)).toBe(99); 30 | 31 | }); 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /client/core/models/hint.ts: -------------------------------------------------------------------------------- 1 | import {Loadable} from "./loadable"; 2 | 3 | export class Hint extends Loadable { 4 | 5 | public id: number; 6 | public question: string; 7 | public index: string; 8 | public answers: [{ 9 | answer: string, 10 | spoiler: boolean, 11 | }]; 12 | 13 | // these are used by the display logic 14 | public current_index = 0; 15 | public is_open = false; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /client/core/models/history-entry.spec.ts: -------------------------------------------------------------------------------- 1 | import {HistoryEntry} from "./history-entry"; 2 | 3 | describe("History entry class", function() { 4 | 5 | test("command and result", function() { 6 | const h = new HistoryEntry("get all"); 7 | expect(h.command).toEqual("get all"); 8 | 9 | h.push("Sword taken", "normal"); 10 | expect(h.results).toEqual([ 11 | {markdown: false, text: "Sword taken", type: "normal"} 12 | ]); 13 | 14 | h.push("The dragon attacks you!", "danger"); 15 | expect(h.results).toEqual([ 16 | {markdown: false, text: "Sword taken", type: "normal"}, 17 | {markdown: false, text: "The dragon attacks you!", type: "danger"} 18 | ]); 19 | 20 | }); 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /client/core/models/history-entry.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Class HistoryEntry. 3 | * Holds the commands and results run previously. 4 | */ 5 | export class HistoryEntry { 6 | 7 | public command: string; 8 | public results: { 9 | text: string, 10 | type: string, 11 | markdown: boolean 12 | }[] = []; 13 | 14 | constructor(command) { 15 | this.command = command; 16 | } 17 | 18 | public push(text: string, type: string, markdown = false) { 19 | if (text === null) { 20 | text = ""; 21 | } 22 | const split_text = text.split(/\n/g); 23 | for (const i in split_text) { 24 | this.results.push({ text: split_text[i], type, markdown }); 25 | } 26 | } 27 | 28 | public append(text: string) { 29 | // TODO: make appends not take any time 30 | this.results[this.results.length - 1].text += text; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /client/core/models/loadable.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Loadable class. Parent class for all objects loaded from the database. 3 | */ 4 | export abstract class Loadable { 5 | 6 | /** 7 | * Loads data from JSON source into the object properties. 8 | * @param Object source an object, e.g., from JSON. 9 | */ 10 | init(source) { 11 | for (const prop in source) { 12 | this[prop] = source[prop]; 13 | } 14 | 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /client/core/models/room.spec.ts: -------------------------------------------------------------------------------- 1 | import {Room} from "./room"; 2 | import {RoomExit} from "./room"; 3 | 4 | import {ROOMS} from "../../adventures/demo1/mock-data/rooms"; 5 | 6 | describe("Room exits", function() { 7 | 8 | const r1 = new Room(); 9 | r1.init(ROOMS[0]); 10 | 11 | it("should get the room to the north", function() { 12 | const x = r1.getExit("n"); 13 | expect(x.direction).toEqual("n"); 14 | expect(x.room_to).toEqual(2); 15 | }); 16 | 17 | it("should get the room to the south", function() { 18 | const x = r1.getExit("s"); 19 | expect(x.direction).toEqual("s"); 20 | expect(x.room_to).toEqual(RoomExit.EXIT); 21 | }); 22 | 23 | it("should NOT get the room to the east", function() { 24 | expect(r1.getExit("e")).toEqual(null); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /client/core/repositories/hint.repo.ts: -------------------------------------------------------------------------------- 1 | import {Hint} from "../models/hint"; 2 | 3 | /** 4 | * Class HintRepository. 5 | * Storage class for all hint data. 6 | */ 7 | export default class HintRepository { 8 | 9 | /** 10 | * An array of all the Hint objects 11 | */ 12 | all: Hint[] = []; 13 | 14 | /** 15 | * The highest ID in the system 16 | */ 17 | index = 0; 18 | 19 | constructor(hint_data: Array>) { 20 | for (const i of hint_data) { 21 | this.add(i); 22 | } 23 | } 24 | 25 | /** 26 | * Adds a hint. 27 | * @param {Object} hint_data 28 | */ 29 | public add(hint_data): Hint { 30 | const h = new Hint(); 31 | 32 | h.init(hint_data); 33 | 34 | // autonumber the ID if not provided 35 | if (h.id === undefined) { 36 | h.id = this.index + 1; 37 | } 38 | 39 | if (this.get(h.id) !== null) { 40 | throw new Error("Tried to create a hint #" + h.id + " but that ID is already taken."); 41 | } 42 | 43 | this.all.push(h); 44 | 45 | // update the autonumber index 46 | if (h.id > this.index) { 47 | this.index = h.id; 48 | } 49 | return h; 50 | } 51 | 52 | /** 53 | * Gets a hint by id. 54 | * @param {number} id 55 | * @return Monster 56 | */ 57 | public get(id): Hint|null { 58 | const h = this.all.find(x => x.id === id); 59 | return h || null; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /client/core/types.ts: -------------------------------------------------------------------------------- 1 | import Game from "./models/game"; 2 | 3 | /** 4 | * Common type for components that take the Game object as a prop 5 | */ 6 | export type PropsWithGame = { 7 | game: Game; 8 | setGameState: (game: Game) => void; 9 | } 10 | 11 | 12 | /** 13 | * Props used by hints, command list, and how to play modal 14 | */ 15 | export type ModalProps = { 16 | game: Game; 17 | visible: boolean; 18 | toggle: () => void; 19 | } 20 | -------------------------------------------------------------------------------- /client/core/utils/command.exception.ts: -------------------------------------------------------------------------------- 1 | export declare class Error { 2 | public name: string; 3 | public message: string; 4 | public stack: string; 5 | constructor(message?: string); 6 | } 7 | 8 | export class CommandException extends Error { 9 | 10 | constructor(m: string) { 11 | super(m); 12 | this.name = "Exception"; 13 | 14 | // Set the prototype explicitly. 15 | Object.setPrototypeOf(this, CommandException.prototype); 16 | } 17 | 18 | toString() { 19 | return this.name + ": " + this.message; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /client/core/utils/logger.interface.ts: -------------------------------------------------------------------------------- 1 | export interface ILoggerService { 2 | log(type: string, value?: number); 3 | } 4 | 5 | /** 6 | * Dummy logger used with automated tests 7 | */ 8 | export class DummyLoggerService implements ILoggerService { 9 | 10 | public log(type = "", value: number = null) { 11 | // this logger class prints its log entries to the console. It doesn't save anything to the DB. 12 | console.log("Log: ", type, value); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /client/core/utils/logger.ts: -------------------------------------------------------------------------------- 1 | import {ILoggerService} from "./logger.interface"; 2 | import {getAxios} from "../../main-hall/utils/api"; 3 | import Game from "../models/game"; 4 | 5 | declare let game: Game; 6 | 7 | /** 8 | * Real live logger class connected to API 9 | */ 10 | export default class Logger implements ILoggerService { 11 | 12 | public log(type = "", value: number = null) { 13 | const body = { 14 | 'player': game.demo ? null : window.localStorage.getItem('player_id'), 15 | 'adventure': game.id, 16 | 'type': type, 17 | 'value': value 18 | }; 19 | const axios = getAxios(); 20 | axios.post('/log', body) 21 | .catch(err => { 22 | console.error('logger error', err); 23 | }); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /client/core/utils/saved-game.interface.ts: -------------------------------------------------------------------------------- 1 | // import { EMPTY } from 'rxjs'; 2 | 3 | export interface ISavedGameService { 4 | saveGame(data: any); 5 | listSavedGames(player_id: any, adventure_id: number); 6 | loadSavedGame(saved_game: any); 7 | loadSavedGameById(id: number); 8 | deleteSavedGame(saved_game: any); 9 | } 10 | 11 | /** 12 | * Dummy service used with automated tests 13 | */ 14 | export class DummySavedGameService implements ISavedGameService { 15 | 16 | public saveGame(data: any) { 17 | } 18 | 19 | public listSavedGames(player_id: any, adventure_id: number) { 20 | // this used to return an empty Observable, but that just confused Webpack, so 21 | // it got refactored to return undefined 22 | return undefined; 23 | // return EMPTY; 24 | } 25 | 26 | public loadSavedGame(saved_game: any) { 27 | } 28 | 29 | public loadSavedGameById(id: number) { 30 | } 31 | 32 | public deleteSavedGame(saved_game: any) { 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /client/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:8000" 3 | } 4 | -------------------------------------------------------------------------------- /client/cypress/fixtures/adv1/adventure.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 0, 3 | "name": "Test Adv 1", 4 | "description": "Welcome to the demo! This is a simple adventure used for development and automated tests. You will be exploring a small castle.", 5 | "intro_text": "This is some intro text" 6 | } 7 | -------------------------------------------------------------------------------- /client/cypress/fixtures/adv1/artifacts.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "name": "rocket launcher", 5 | "description": "This is a rocket launcher.", 6 | "type": 3, 7 | "room_id": 1, 8 | "weight": 10, 9 | "value": 250 10 | } 11 | ] 12 | -------------------------------------------------------------------------------- /client/cypress/fixtures/adv1/effects.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /client/cypress/fixtures/adv1/monsters.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /client/cypress/fixtures/adv1/rooms.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "name": "Entrance", 5 | "description": "You are standing at the entrance.", 6 | "exits": [ 7 | {"direction": "s", "room_to": -999} 8 | ] 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /client/cypress/fixtures/adventures.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "name": "Test Adv 1", 5 | "description": "This is the description", 6 | "full_description": "", 7 | "intro_text": "", 8 | "intro_question": "", 9 | "slug": "demo1", 10 | "edx": "n/a", 11 | "dead_body_id": 0, 12 | "featured_month": "", 13 | "date_published": "2021-01-01", 14 | "authors": [ 15 | "Donald Brown" 16 | ], 17 | "tags": [ 18 | "tag1" 19 | ], 20 | "times_played": 100, 21 | "avg_ratings": { 22 | "overall__avg": 4.1, 23 | "combat__avg": 3.2, 24 | "puzzle__avg": 3.2 25 | } 26 | }, 27 | 28 | { 29 | "id": 2, 30 | "name": "Test Adv 2", 31 | "description": "This is the description", 32 | "full_description": "", 33 | "intro_text": "", 34 | "intro_question": "", 35 | "slug": "demo2", 36 | "edx": "n/a", 37 | "dead_body_id": 0, 38 | "featured_month": "", 39 | "date_published": "2022-01-01", 40 | "authors": [ 41 | "Tom Zuchowski" 42 | ], 43 | "tags": [ 44 | "tag2" 45 | ], 46 | "times_played": 200, 47 | "avg_ratings": { 48 | "overall__avg": 4.3, 49 | "combat__avg": 3.5, 50 | "puzzle__avg": 3.6 51 | } 52 | } 53 | ] -------------------------------------------------------------------------------- /client/cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************************** 3 | // This example plugins/index.js can be used to load plugins 4 | // 5 | // You can change the location of this file or turn off loading 6 | // the plugins file with the 'pluginsFile' configuration option. 7 | // 8 | // You can read more here: 9 | // https://on.cypress.io/plugins-guide 10 | // *********************************************************** 11 | 12 | // This function is called when a project is opened or re-opened (e.g. due to 13 | // the project's config changing) 14 | 15 | /** 16 | * @type {Cypress.PluginConfig} 17 | */ 18 | // eslint-disable-next-line no-unused-vars 19 | module.exports = (on, config) => { 20 | // `on` is used to hook into various events Cypress emits 21 | // `config` is the resolved Cypress config 22 | } 23 | -------------------------------------------------------------------------------- /client/cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add('login', (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) 26 | 27 | import 'cypress-wait-until'; 28 | -------------------------------------------------------------------------------- /client/cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /client/cypress/support/page_objects/adventurePage.js: -------------------------------------------------------------------------------- 1 | export class AdventurePage { 2 | 3 | enterCommand(command) { 4 | cy.get('#command').type(`${command}{enter}`); 5 | cy.wait(500); 6 | } 7 | 8 | clickModalButton(text) { 9 | cy.contains('.game-modal button', text).click(); 10 | } 11 | 12 | clickReturnButton(text) { 13 | cy.get('button#return').click({force: true}); 14 | } 15 | 16 | clickSaveButton(text) { 17 | cy.contains('button', 'Save and go to main hall').click(); 18 | } 19 | 20 | } 21 | 22 | export const onAdventurePage = new AdventurePage(); 23 | -------------------------------------------------------------------------------- /client/cypress/support/page_objects/mainHallPage.js: -------------------------------------------------------------------------------- 1 | export class MainHallPage { 2 | 3 | goToAdventures() { 4 | cy.contains('a', 'Go on an adventure').click(); 5 | } 6 | 7 | goToShop() { 8 | cy.contains('a', 'Visit the weapons shop').click(); 9 | } 10 | 11 | goToBank() { 12 | cy.contains('a', 'Find the banker to deposit or withdraw some gold').click(); 13 | } 14 | 15 | goToWizard() { 16 | cy.contains('a', 'Find a wizard to teach you some spells').click(); 17 | } 18 | 19 | goToWitch() { 20 | cy.contains('a', 'Visit the witch to increase your attributes').click(); 21 | } 22 | 23 | logOut() { 24 | cy.contains('a', 'Temporarily leave the universe').click(); 25 | } 26 | 27 | } 28 | 29 | export const onMainHallPage = new MainHallPage(); 30 | -------------------------------------------------------------------------------- /client/cypress/support/page_objects/shopPage.js: -------------------------------------------------------------------------------- 1 | export class ShopPage { 2 | 3 | goToBuyPage() { 4 | cy.contains('a', 'Buy weapons').click(); 5 | } 6 | 7 | goToSellPage() { 8 | cy.contains('a', 'Sell weapons').click(); 9 | } 10 | 11 | returnToMenu() { 12 | cy.contains('a', 'Done').click(); 13 | } 14 | 15 | leaveShop() { 16 | cy.contains('a', 'Go back to Main Hall').click(); 17 | } 18 | 19 | expectGoldAmount(amount) { 20 | cy.get('[data-qa="goldAmount"]').should('have.text', amount); 21 | } 22 | 23 | } 24 | 25 | export const onShopPage = new ShopPage(); 26 | -------------------------------------------------------------------------------- /client/designer/components/AdventureHeading.tsx: -------------------------------------------------------------------------------- 1 | import {Link} from "react-router-dom"; 2 | import * as React from "react"; 3 | import AdventureContext from "../contexts/adventure"; 4 | import {useParams} from "react-router-dom"; 5 | 6 | 7 | const AdventureHeading: React.FC = () => { 8 | const adventureContext = React.useContext(AdventureContext); 9 | const params = useParams(); 10 | const slug = params['*'].split('/')[0]; 11 | 12 | if (!adventureContext.adventure) { 13 | return

Loading {slug}...

; 14 | } 15 | 16 | return ( 17 |
18 |
19 | Map 20 |
21 |
22 |
#{adventureContext.adventure.id}
24 |

{adventureContext.adventure.name}

25 |

{adventureContext.adventure.authors_display.length ? "By: " + adventureContext.adventure.authors_display : ""}

26 |
27 |
28 | ); 29 | 30 | } 31 | 32 | export default AdventureHeading; 33 | -------------------------------------------------------------------------------- /client/designer/components/EffectList.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Link } from "react-router-dom"; 3 | 4 | import AdventureContext from "../contexts/adventure"; 5 | import {TextStyleLabel} from "./common"; 6 | 7 | 8 | const EffectList: React.FC = () => { 9 | const context = React.useContext(AdventureContext); 10 | 11 | if (!context.adventure) { 12 | return

Loading...

; 13 | } 14 | 15 | let emptyMessage = ''; 16 | if (!context.effects.all.length) { 17 | emptyMessage = 'no effects yet'; 18 | } 19 | 20 | return ( 21 |
22 |

Effects

23 | 24 |

Choose an effect:

25 | 26 |
27 |
28 | {emptyMessage} 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | {context.effects?.all.map(eff => { 39 | return ( 40 | 41 | 42 | 43 | 44 | 45 | ); 46 | })} 47 | 48 |
#TextStyle
{eff.id}{eff.text}
49 |
50 |
51 |
52 | ); 53 | } 54 | 55 | export default EffectList; 56 | -------------------------------------------------------------------------------- /client/designer/components/RoomList.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import AdventureContext from "../contexts/adventure"; 4 | import {RoomLink} from "./common"; 5 | 6 | 7 | const RoomList: React.FC = () => { 8 | const context = React.useContext(AdventureContext); 9 | 10 | if (!context.adventure) { 11 | return

Loading...

; 12 | } 13 | 14 | let emptyMessage = ''; 15 | if (!context.rooms.all.length) { 16 | emptyMessage = 'no rooms yet'; 17 | } 18 | 19 | return ( 20 |
21 |

Rooms

22 | 23 |

Choose a room:

24 | 25 |
26 |
27 | {emptyMessage} 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {context.rooms.all.map((room) => { 37 | return ( 38 | 39 | 40 | 41 | 42 | ); 43 | })} 44 | 45 |
#Name
{room.id}
46 |
47 |
48 |
49 | ); 50 | } 51 | 52 | export default RoomList; 53 | -------------------------------------------------------------------------------- /client/designer/constants.ts: -------------------------------------------------------------------------------- 1 | export enum ArtifactTypes { 2 | GOLD = 0, 3 | TREASURE = 1, 4 | WEAPON = 2, 5 | MAGIC_WEAPON = 3, 6 | CONTAINER = 4, 7 | LIGHT_SOURCE = 5, 8 | DRINKABLE = 6, 9 | READABLE = 7, 10 | DOOR = 8, 11 | EDIBLE = 9, 12 | BOUND_MONSTER = 10, 13 | WEARABLE = 11, 14 | DISGUISED_MONSTER = 12, 15 | DEAD_BODY = 13, 16 | USER_1 = 14, 17 | USER_2 = 15, 18 | USER_3 = 16 19 | } 20 | 21 | export enum ArtifactIcons { 22 | GOLD = 'coin', 23 | TREASURE = 'gem', 24 | WEAPON = 'sword', 25 | MAGIC_WEAPON = 'sword2', 26 | CONTAINER = 'backpack', 27 | LIGHT_SOURCE = 'star', 28 | DRINKABLE = 'potion', 29 | READABLE = 'tome', 30 | DOOR = 'tools', 31 | EDIBLE = 'star', 32 | BOUND_MONSTER = 'star', 33 | WEARABLE = 'boots', 34 | DISGUISED_MONSTER = 'star', 35 | DEAD_BODY = 'star', 36 | USER_1 = 'tools', 37 | USER_2 = 'tools', 38 | USER_3 = 'tools' 39 | } 40 | -------------------------------------------------------------------------------- /client/designer/contexts/form.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | interface FormContextInterface { 4 | setField: (ev: React.ChangeEvent) => void, 5 | saveField: (ev: React.ChangeEvent) => void, 6 | } 7 | const FormContext = React.createContext(null); 8 | 9 | export default FormContext; 10 | -------------------------------------------------------------------------------- /client/designer/contexts/user.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | interface UserContextInterface { 4 | username: string, 5 | token: string, 6 | changeUserState: (username: string, token: string, refresh_token: string) => void, 7 | getToken: () => Promise, 8 | } 9 | const UserContext = React.createContext(null); 10 | 11 | export default UserContext; 12 | -------------------------------------------------------------------------------- /client/designer/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDOM from 'react-dom'; 3 | import Designer from './components/Designer'; 4 | 5 | ReactDOM.render( 6 | , 7 | document.getElementById('root') as HTMLElement 8 | ); 9 | -------------------------------------------------------------------------------- /client/designer/models/adventure.ts: -------------------------------------------------------------------------------- 1 | import GameObject from "./game-object"; 2 | 3 | /** 4 | * Adventure class. Represents adventures the player can go on. 5 | */ 6 | export default class Adventure extends GameObject { 7 | 8 | name_sort: string; 9 | description: string; 10 | full_description: string; 11 | intro_text: string; 12 | slug: string; 13 | featured_month: string; 14 | date_published: string; 15 | times_played: string; 16 | authors: string[]; 17 | authors_display: string; 18 | tags: string[]; 19 | active: boolean; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /client/designer/models/effect.ts: -------------------------------------------------------------------------------- 1 | import GameObject from "./game-object"; 2 | 3 | /** 4 | * Effect class. Represents special effect text that can be displayed 5 | * by scripts during game play. 6 | */ 7 | export class Effect extends GameObject { 8 | 9 | id: number; 10 | text: string; 11 | style: string; 12 | next: number; // another effect chained onto this one 13 | next_inline: number; // a chained effect that is printed without a paragraph break 14 | replacements: Record; // strings that will be replaced within the effect text 15 | 16 | public excerpt(): string { 17 | if (this.text.length <= 50) { 18 | return this.text; 19 | } 20 | return this.text.slice(0, 50) + '...'; 21 | } 22 | 23 | } 24 | 25 | export const TEXT_STYLES = { 26 | '': 'Normal', 27 | 'emphasis': 'Bold', 28 | 'success': 'Success (green)', 29 | 'special': 'Special 1 (blue)', 30 | 'special2': 'Special 1 (purple)', 31 | 'warning': 'Warning (orange)', 32 | 'danger': 'Danger (red)', 33 | } 34 | -------------------------------------------------------------------------------- /client/designer/models/game-object.ts: -------------------------------------------------------------------------------- 1 | import { v4 as uuidv4 } from 'uuid'; 2 | 3 | /** 4 | * GameObject class. Parent class for monsters and artifacts. 5 | */ 6 | export default class GameObject { 7 | 8 | /** 9 | * The "id" is the database ID. Objects will only have a value for this if 10 | * they were saved to the DB (e.g., adventures, rooms, player artifacts) 11 | * (Artifacts created in the shop in the mail hall won't have this until they are saved.) 12 | */ 13 | id: number; 14 | 15 | /** 16 | * The UUID is a temporary identifier used as a key for React elements. 17 | * It is not persisted to the database and doesn't need to be. 18 | */ 19 | uuid: string; 20 | article: string; 21 | name: string; 22 | description: string; 23 | is_markdown: boolean; 24 | effect: number; 25 | effect_inline: number; 26 | synonyms: string; 27 | 28 | /** 29 | * Loads data from JSON source into the object properties. 30 | * @param {Record} source an object, e.g., from JSON. 31 | */ 32 | public init(source: Record): void { 33 | this.uuid = uuidv4(); 34 | for (const prop in source) { 35 | if (source.hasOwnProperty(prop)) { 36 | this[prop] = source[prop]; 37 | } 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /client/designer/models/hint.ts: -------------------------------------------------------------------------------- 1 | import {Loadable} from "./loadable"; 2 | 3 | export default class Hint extends Loadable { 4 | 5 | public id: number; 6 | public question: string; 7 | public index: string; 8 | public answers: Array>; 9 | 10 | // these are used by the display logic 11 | public current_index = 0; 12 | public is_open = false; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /client/designer/models/loadable.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Loadable class. Parent class for all objects loaded from the database. 3 | */ 4 | export abstract class Loadable { 5 | 6 | /** 7 | * Loads data from JSON source into the object properties. 8 | * @param Object source an object, e.g., from JSON. 9 | */ 10 | init(source) { 11 | for (const prop in source) { 12 | this[prop] = source[prop]; 13 | } 14 | 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /client/designer/repositories/base.repo.ts: -------------------------------------------------------------------------------- 1 | export class BaseRepository { 2 | 3 | /** 4 | * An array of all the Artifact objects 5 | */ 6 | all: any[]; 7 | 8 | /** 9 | * Gets the array index of a numbered artifact. 10 | * @param {number} id 11 | * @return number 12 | */ 13 | getIndex(id: number | string): number { 14 | if (typeof id === 'string') id = parseInt(id); 15 | return this.all.findIndex(x => x.id === id); 16 | } 17 | 18 | /** 19 | * Gets the index of the previous object in the repository. Can 20 | * handle sparse numbering. 21 | * 22 | * @param {number} id 23 | * @return number 24 | */ 25 | getPrev(id: number | string): number { 26 | if (typeof id === 'string') id = parseInt(id); 27 | const ids = this.all 28 | .filter(a => a.id < id) 29 | .map(a => a.id) 30 | .sort((a, b) => b - a); // `b - a` sorts in reverse order 31 | return ids.length ? ids[0] : null; 32 | } 33 | 34 | /** 35 | * Gets the index of the next object in the repository. Can 36 | * handle sparse numbering. 37 | * 38 | * @param {number} id 39 | * @return number 40 | */ 41 | getNext(id: number | string): number { 42 | if (typeof id === 'string') id = parseInt(id); 43 | const ids = this.all 44 | .filter(a => a.id > id) 45 | .map(a => a.id) 46 | .sort((a, b) => a - b); 47 | return ids.length ? ids[0] : null; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /client/designer/repositories/hint.repo.ts: -------------------------------------------------------------------------------- 1 | import Hint from "../models/hint"; 2 | 3 | /** 4 | * Class HintRepository. 5 | * Storage class for all hint data. 6 | */ 7 | export default class HintRepository { 8 | 9 | /** 10 | * An array of all the Hint objects 11 | */ 12 | all: Hint[] = []; 13 | 14 | /** 15 | * The highest ID in the system 16 | */ 17 | index = 0; 18 | 19 | constructor(hint_data: Array>) { 20 | for (const i of hint_data) { 21 | this.add(i); 22 | } 23 | } 24 | 25 | /** 26 | * Adds a hint. 27 | * @param {Record} hint_data 28 | */ 29 | public add(hint_data: Record): Hint { 30 | const h = new Hint(); 31 | 32 | h.init(hint_data); 33 | 34 | // autonumber the ID if not provided 35 | if (h.id === undefined) { 36 | h.id = this.index + 1; 37 | } 38 | 39 | if (this.get(h.id) !== null) { 40 | throw new Error("Tried to create a hint #" + h.id + " but that ID is already taken."); 41 | } 42 | 43 | this.all.push(h); 44 | 45 | // update the autonumber index 46 | if (h.id > this.index) { 47 | this.index = h.id; 48 | } 49 | return h; 50 | } 51 | 52 | /** 53 | * Gets a hint by id. 54 | * @param {number} id 55 | * @return Hint 56 | */ 57 | public get(id: number): Hint|null { 58 | const h = this.all.find(x => x.id === id); 59 | return h || null; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /client/designer/repositories/room.repo.ts: -------------------------------------------------------------------------------- 1 | import {Room} from "../models/room"; 2 | import {BaseRepository} from "./base.repo"; 3 | import {roomSource} from "../types"; 4 | 5 | /** 6 | * Class RoomRepository. 7 | * Storage class for all room data. 8 | */ 9 | export default class RoomRepository extends BaseRepository { 10 | 11 | /** 12 | * An array of all the Room objects 13 | */ 14 | all: Room[] = []; 15 | 16 | /** 17 | * The object representing the room the player is currently in 18 | */ 19 | current_room: Room; 20 | 21 | constructor(room_data: Array) { 22 | super(); 23 | for (const i of room_data) { 24 | const r = new Room(); 25 | r.init(i); 26 | this.all.push(r); 27 | } 28 | } 29 | 30 | /** 31 | * Gets a numbered room. 32 | * @param {number} id 33 | * @return Room 34 | */ 35 | get(id: number|string): Room { 36 | if (typeof id === 'string') id = parseInt(id); 37 | const r = this.all.find(x => x.id === id); 38 | return r || null; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /client/designer/types.ts: -------------------------------------------------------------------------------- 1 | 2 | export type RouteParams = { 3 | slug: string, 4 | id?: string 5 | } 6 | 7 | export type roomSource = { 8 | id: number, 9 | name: string, 10 | exits: Record[] 11 | } 12 | -------------------------------------------------------------------------------- /client/jest.config.mjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | "maxWorkers": 1, 3 | "moduleFileExtensions": [ 4 | "js", 5 | "jsx", 6 | "ts", 7 | "tsx" 8 | ], 9 | "preset": "ts-jest", 10 | "setupFiles": ['./jest.setup.js'], 11 | "setupFilesAfterEnv": ["jest-expect-message"], 12 | "testEnvironment": "jsdom", 13 | "testMatch": [ 14 | "**/__tests__/**/*.ts?(x)", 15 | "**/?(*.)+(spec|test).ts?(x)" 16 | ], 17 | "testPathIgnorePatterns": [ 18 | "/node_modules/", 19 | "/adventures/base-adventure/" 20 | ], 21 | "transformIgnorePatterns": [ 22 | "/node_modules/(?!(axios|uuid))" 23 | ], 24 | "testEnvironmentOptions": { 25 | "url": "http://localhost:8000/" 26 | } 27 | } 28 | 29 | export default config; 30 | -------------------------------------------------------------------------------- /client/jest.setup.js: -------------------------------------------------------------------------------- 1 | // This ensures you can use `window.fetch()` in your Jest tests. 2 | require('whatwg-fetch') 3 | -------------------------------------------------------------------------------- /client/main-hall/components/MainHall.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import {BrowserRouter as Router, Route, Routes} from "react-router-dom"; 3 | import PlayerCreate from "./PlayerCreate"; 4 | import PlayerDetail from "./PlayerDetail"; 5 | import PlayerList from "./PlayerList"; 6 | 7 | const MainHall = () => { 8 | return ( 9 |
10 |
11 |
12 | 13 | 14 | }/> 15 | }/> 16 | {/* non-exact route below is used so we can have child routes inside the component */} 17 | }/> 18 | 19 | 20 |
21 |
22 |
23 | ); 24 | } 25 | 26 | export default MainHall; 27 | -------------------------------------------------------------------------------- /client/main-hall/hooks.ts: -------------------------------------------------------------------------------- 1 | import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux' 2 | import type { RootState, AppDispatch } from './store' 3 | 4 | // Use throughout your app instead of plain `useDispatch` and `useSelector` 5 | export const useAppDispatch = () => useDispatch() 6 | export const useAppSelector: TypedUseSelectorHook = useSelector 7 | 8 | export const usePlayer = () => { 9 | const dispatch = useAppDispatch(); 10 | const player = useAppSelector((state) => state.player); 11 | const genderLabel = useAppSelector((state) => { 12 | return state.player.gender === 'm' ? "mighty" : "fair"; 13 | }) 14 | 15 | return { 16 | dispatch, 17 | player, 18 | genderLabel, 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /client/main-hall/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDOM from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import MainHall from './components/MainHall'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | import store from './store/index'; 7 | 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | document.getElementById('root') as HTMLElement 13 | ); 14 | registerServiceWorker(); 15 | -------------------------------------------------------------------------------- /client/main-hall/models/adventure.ts: -------------------------------------------------------------------------------- 1 | import GameObject from "./game-object"; 2 | 3 | /** 4 | * Adventure class. Represents adventures the player can go on. 5 | */ 6 | export default interface Adventure extends GameObject { 7 | 8 | name_sort: string; 9 | description: string; 10 | full_description: string; 11 | slug: string; 12 | featured_month: string; 13 | date_published: string; 14 | times_played: string; 15 | authors: string[]; 16 | authors_display: string; 17 | tags: string[]; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /client/main-hall/models/game-object.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * GameObject class. Parent class for monsters and artifacts. 3 | */ 4 | export default interface GameObject { 5 | /** 6 | * The "id" is the database ID. Objects will only have a value for this if 7 | * they were saved to the DB (e.g., adventures, rooms, player artifacts) 8 | * (Artifacts created in the shop in the mail hall won't have this until they are saved.) 9 | */ 10 | id: number; 11 | 12 | /** 13 | * The UUID is a temporary identifier used as a key for React elements. 14 | * It is not persisted to the database and doesn't need to be. 15 | */ 16 | uuid: string; 17 | name: string; 18 | description: string; 19 | } 20 | -------------------------------------------------------------------------------- /client/main-hall/store/index.ts: -------------------------------------------------------------------------------- 1 | import { configureStore } from '@reduxjs/toolkit'; 2 | 3 | import playerReducer from './player'; 4 | // import authReducer from './auth'; 5 | 6 | 7 | const store = configureStore({ 8 | reducer: { player: playerReducer }, 9 | middleware: (getDefaultMiddleware) => 10 | getDefaultMiddleware({ 11 | serializableCheck: { 12 | // Ignore these action types 13 | ignoredActions: ['player/setPlayer'], 14 | // Ignore these paths in the state 15 | ignoredPaths: ['player'], 16 | }, 17 | }), 18 | }); 19 | 20 | export default store; 21 | 22 | // Infer the `RootState` and `AppDispatch` types from the store itself 23 | export type RootState = ReturnType 24 | // Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState} 25 | export type AppDispatch = typeof store.dispatch 26 | -------------------------------------------------------------------------------- /client/main-hall/tests/MainHall.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDOM from 'react-dom'; 3 | import MainHall from '../components/MainHall'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /client/main-hall/tests/Player.test.ts: -------------------------------------------------------------------------------- 1 | import Player, {updateCachedInfo} from "../models/player"; 2 | import Artifact, {ARMOR_TYPES, ARTIFACT_TYPES} from "../models/artifact"; 3 | 4 | let player; 5 | 6 | beforeEach(() => { 7 | player = {} as Player; 8 | const artifact1 = { 9 | 'name': 'trollsfire', 10 | 'type': ARTIFACT_TYPES.WEAPON, 11 | 'dice': 2, 12 | 'sides': 10 13 | } as Artifact; 14 | const artifact2 = { 15 | 'name': 'axe', 16 | 'type': ARTIFACT_TYPES.WEAPON, 17 | 'dice': 1, 18 | 'sides': 6 19 | } as Artifact; 20 | const artifact3 = { 21 | 'name': 'leather armor', 22 | 'type': ARTIFACT_TYPES.WEARABLE, 23 | 'armor_type': ARMOR_TYPES.ARMOR, 24 | 'armor_class': 1 25 | } as Artifact; 26 | player.inventory = [artifact1, artifact2, artifact3]; 27 | updateCachedInfo(player); 28 | }); 29 | 30 | it('can determine best weapon and armor', () => { 31 | expect(player.best_weapon.name).toBe('trollsfire'); 32 | expect(player.best_armor.name).toBe('leather armor'); 33 | }); 34 | -------------------------------------------------------------------------------- /client/main-hall/utils/dice.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Rolls a set of dice 4 | */ 5 | export default function diceRoll(dice: number, sides: number): number { 6 | let result = 0; 7 | for (let i = 0; i < dice; i++) { 8 | result += Math.floor(Math.random() * sides + 1); 9 | } 10 | return result; 11 | } 12 | -------------------------------------------------------------------------------- /client/main-hall/utils/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Main utilities file. Contains a bunch of utility functions like "titleCase" and "percentOrNone". 3 | */ 4 | 5 | /** 6 | * Title Case function. 7 | * 8 | * Example of usage: 9 | * 10 | * ``` 11 | * import { titleCase } from "../utils" 12 | * const str = 'foo bar'; 13 | * console.log(titleCase(str)); // outputs "Foo Bar" 14 | * ``` 15 | * 16 | * @param {string} input 17 | * @return {string} 18 | */ 19 | export function titleCase(input: string): string { 20 | if (!input) { 21 | return ''; 22 | } else { 23 | return input.replace(/\w\S*/g, (txt => txt[0].toUpperCase() + txt.substr(1).toLowerCase() )); 24 | } 25 | } 26 | 27 | /** 28 | * Capitalizes the first letter of a string. 29 | * From https://dzone.com/articles/how-to-capitalize-the-first-letter-of-a-string-in 30 | * @return string 31 | * @param {string} str 32 | */ 33 | export function ucFirst(str: string): string { 34 | return str.charAt(0).toUpperCase() + str.slice(1); 35 | } 36 | 37 | /** 38 | * Outputs the input as a number shown with a percent sign, unless the input is 39 | * zero or not a valid number, in which case it outputs "none" 40 | * 41 | * @param {string} input 42 | * @return string 43 | */ 44 | export function percentOrNone(input: string): string { 45 | const n = parseFloat(input); 46 | if (n === 0 || isNaN(n)) { 47 | return 'none'; 48 | } else { 49 | return n + "%"; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/client/public/favicon.ico -------------------------------------------------------------------------------- /client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | -------------------------------------------------------------------------------- /client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "jsx": "react", 5 | "lib": ["es5", "es6", "dom"], 6 | "module": "commonjs", 7 | "noImplicitAny": false, 8 | "outDir": "./dist/", 9 | "sourceMap": true, 10 | "target": "es5", 11 | }, 12 | "include": [ 13 | "./main-hall/**/*", 14 | "./core/**/*" 15 | ], 16 | "files": ["node_modules/jest-expect-message/types/index.d.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /client/tsconfig.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json" 3 | } -------------------------------------------------------------------------------- /client/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs" 5 | } 6 | } -------------------------------------------------------------------------------- /client/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "linterOptions": { 4 | "exclude": [ 5 | "config/**/*.js", 6 | "node_modules/**/*.ts", 7 | "coverage/lcov-report/*.js" 8 | ] 9 | }, 10 | "rules": { 11 | "forin": false, 12 | "jsx-no-lambda": false, 13 | "member-access": false, 14 | "member-ordering": false, 15 | "no-console": false, 16 | "no-debugger": false, 17 | "no-empty": false, 18 | "object-literal-sort-keys": false, 19 | "ordered-imports": false, 20 | "prefer-const": false, 21 | "variable-name": false 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /db/eamon.sqlite3.dist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/db/eamon.sqlite3.dist -------------------------------------------------------------------------------- /db/query magic wand type weapons.sql: -------------------------------------------------------------------------------- 1 | SELECT * FROM adventure_artifact WHERE (NAME LIKE '%magic%' OR NAME LIKE '%wand%' OR NAME LIKE '%orb%') AND TYPE IN (2,3) AND weapon_type = 2 AND NAME != 'magic bow' 2 | UNION 3 | SELECT * FROM adventure_artifact WHERE NAME = 'Magic blue sphere' -- from prince's tavern -------------------------------------------------------------------------------- /db/room exits for adventure.sql: -------------------------------------------------------------------------------- 1 | SELECT r.room_id, r.name, re.direction, re.room_from_id, re.room_to, re.door_id, re.effect_id, re.id 2 | FROM adventure_roomexit re 3 | INNER JOIN adventure_room r ON re.room_from_id = r.id 4 | WHERE r.adventure_id = 1 5 | -------------------------------------------------------------------------------- /designer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/designer/__init__.py -------------------------------------------------------------------------------- /designer/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class DesignerConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'designer' 7 | -------------------------------------------------------------------------------- /designer/templates/designer.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load static %} 3 | 4 | {% block title %}Adventure Designer{% endblock %} 5 | 6 | {% block scripts %} 7 | 8 | {% endblock %} 9 | 10 | {% block content %} 11 | 12 |
Welcome to the Eamon Adventure Designer...
13 | 14 | 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /designer/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from . import views 3 | 4 | urlpatterns = [ 5 | # The following route will match anything starting with "designer" with or without a trailing slash. 6 | # Any routes matched here will be sent to the "designer" react app. 7 | # Additional path info in the route will be handled by the react router. 8 | url(r'^designer', views.designer, name='designer'), 9 | ] 10 | -------------------------------------------------------------------------------- /designer/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | 4 | def designer(request): 5 | """ 6 | The container for the "designer" react app 7 | """ 8 | return render(request, 'designer.html') 9 | -------------------------------------------------------------------------------- /eamon/local_settings_example.py: -------------------------------------------------------------------------------- 1 | DEBUG = True 2 | 3 | # Uncomment the following if you want to use a MySQL database 4 | # instead of SQLite. 5 | # You also need to run `pip install mysqlclient` (But don't freeze it. That package 6 | # should not be listed in Pipfile.) 7 | DATABASES = { 8 | 'default': { 9 | 'ENGINE': 'django.db.backends.mysql', 10 | 'HOST': 'localhost', 11 | 'USER': 'root', 12 | 'PASSWORD': 'root', 13 | 'NAME': 'eamon', 14 | 'OPTIONS': { 15 | 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /eamon/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import include, url 2 | from django.contrib import admin 3 | 4 | from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView 5 | 6 | urlpatterns = [ 7 | url(r'^admin/', admin.site.urls), 8 | 9 | url('api/token/$', TokenObtainPairView.as_view(), name='token_obtain_pair'), 10 | url('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), 11 | 12 | url(r'^', include('adventure.urls')), 13 | url(r'^', include('designer.urls')), 14 | ] 15 | -------------------------------------------------------------------------------- /eamon/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for eamonproj project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | import time 12 | import traceback 13 | import signal 14 | import sys 15 | 16 | from django.core.wsgi import get_wsgi_application 17 | 18 | sys.path.append('/var/www/vhosts/eamon') 19 | sys.path.append('/var/www/vhosts/eamon/venv/lib/python3.5/site-packages') 20 | 21 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "eamon.settings") 22 | 23 | application = get_wsgi_application() 24 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "eamon.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /news/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/news/__init__.py -------------------------------------------------------------------------------- /news/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Article 3 | 4 | 5 | @admin.register(Article) 6 | class ArticleAdmin(admin.ModelAdmin): 7 | list_display = ('__str__', 'created_at') 8 | -------------------------------------------------------------------------------- /news/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class NewsConfig(AppConfig): 5 | name = 'news' 6 | -------------------------------------------------------------------------------- /news/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2017-05-27 07:19 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='Article', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('title', models.CharField(max_length=255)), 21 | ('body', models.TextField()), 22 | ('created_at', models.DateField()), 23 | ], 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /news/migrations/0002_auto_20170527_0125.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2017-05-27 08:25 3 | from __future__ import unicode_literals 4 | 5 | import ckeditor.fields 6 | from django.db import migrations 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('news', '0001_initial'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AlterField( 17 | model_name='article', 18 | name='body', 19 | field=ckeditor.fields.RichTextField(), 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /news/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/news/migrations/__init__.py -------------------------------------------------------------------------------- /news/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from ckeditor.fields import RichTextField 3 | 4 | 5 | class Article(models.Model): 6 | title = models.CharField(max_length=255) 7 | body = RichTextField() 8 | created_at = models.DateField() 9 | 10 | def __str__(self): 11 | return self.title 12 | -------------------------------------------------------------------------------- /news/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | from django.urls import reverse 3 | from .models import Article 4 | 5 | 6 | class ModelsTest(TestCase): 7 | def setUp(self): 8 | Article.objects.create(id=1, title="Clone army invades west coast", 9 | created_at="2019-01-01") 10 | 11 | def test_object(self): 12 | a1 = Article.objects.get(pk=1) 13 | self.assertEqual(str(a1), "Clone army invades west coast") 14 | 15 | 16 | class ViewTests(TestCase): 17 | 18 | def test_news(self): 19 | Article.objects.create(id=1, title="Clone army invades west coast", body="Lorem ipsum...", 20 | created_at="2019-01-01") 21 | Article.objects.create(id=2, title="Pirates spotted in Eamon Harbor", body="more text here", 22 | created_at="2019-01-01") 23 | response = self.client.get(reverse('news')) 24 | self.assertEqual(response.status_code, 200) 25 | self.assertContains(response, "Clone army invades west coast") 26 | self.assertContains(response, "Lorem ipsum") 27 | self.assertContains(response, "Pirates spotted in Eamon Harbor") 28 | self.assertContains(response, "more text here") 29 | -------------------------------------------------------------------------------- /news/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url, include 2 | 3 | from . import views 4 | 5 | urlpatterns = [ 6 | url(r'^$', views.news, name='news'), 7 | ] 8 | -------------------------------------------------------------------------------- /news/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 3 | 4 | from .models import Article 5 | 6 | 7 | def news(request): 8 | article_list = Article.objects.order_by('-created_at') 9 | page = request.GET.get('page', 1) 10 | paginator = Paginator(article_list, 3) 11 | 12 | try: 13 | articles = paginator.page(page) 14 | except PageNotAnInteger: 15 | articles = paginator.page(1) 16 | except EmptyPage: 17 | articles = paginator.page(paginator.num_pages) 18 | 19 | return render(request, 'news.html', {'articles': articles}) 20 | -------------------------------------------------------------------------------- /player/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/player/__init__.py -------------------------------------------------------------------------------- /player/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /player/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class PlayerConfig(AppConfig): 5 | name = 'player' 6 | -------------------------------------------------------------------------------- /player/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0.2 on 2018-04-15 19:02 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ('adventure', '0048_auto_20180304_1832'), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='SavedGame', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('slot', models.IntegerField(null=True)), 21 | ('description', models.CharField(blank=True, default='', max_length=255)), 22 | ('data', models.TextField(max_length=1000000, null=True)), 23 | ('adventure', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='saved_games', to='adventure.Adventure')), 24 | ('player', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='saved_games', to='adventure.Player')), 25 | ], 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /player/migrations/0002_savedgame_created.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.0.4 on 2018-04-30 04:54 2 | 3 | from django.db import migrations, models 4 | import django.utils.timezone 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('player', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='savedgame', 16 | name='created', 17 | field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), 18 | preserve_default=False, 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /player/migrations/0003_rating.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.1 on 2019-07-04 04:49 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('adventure', '0058_auto_20190703_2149'), 11 | ('player', '0002_savedgame_created'), 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Rating', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('uuid', models.CharField(max_length=255, null=True)), 20 | ('overall', models.IntegerField(blank=True, null=True)), 21 | ('combat', models.IntegerField(blank=True, null=True)), 22 | ('puzzle', models.IntegerField(blank=True, null=True)), 23 | ('created', models.DateTimeField(auto_now_add=True, null=True)), 24 | ('adventure', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ratings', to='adventure.Adventure')), 25 | ], 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /player/migrations/0006_alter_savedgame_player.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.12 on 2022-05-15 08:52 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('player', '0005_move_player_data'), 11 | ] 12 | 13 | operations = [ 14 | # migrations.AlterField( 15 | # model_name='savedgame', 16 | # name='player', 17 | # field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='saved_games', to='player.player'), 18 | # ), 19 | ] 20 | -------------------------------------------------------------------------------- /player/migrations/0007_playerprofile_slug.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.6 on 2022-05-21 13:39 2 | 3 | from django.db import migrations, models 4 | from player.models import generate_slug 5 | 6 | 7 | def populate_slug(apps, schema_editor): 8 | Player = apps.get_model('player', 'Player') 9 | PlayerProfile = apps.get_model('player', 'PlayerProfile') 10 | 11 | uuids = Player.objects.values_list('uuid', flat=True).distinct() 12 | for uuid in uuids: 13 | profile = PlayerProfile.objects.get_or_create(uuid=uuid)[0] 14 | print(repr(profile)) 15 | slug = generate_slug() 16 | while PlayerProfile.objects.filter(slug=slug).exists(): 17 | slug = generate_slug() 18 | profile.slug = slug 19 | profile.save() 20 | 21 | 22 | class Migration(migrations.Migration): 23 | 24 | dependencies = [ 25 | ('player', '0006_alter_savedgame_player'), 26 | ] 27 | 28 | operations = [ 29 | migrations.AddField( 30 | model_name='playerprofile', 31 | name='slug', 32 | field=models.CharField(max_length=6, null=True), 33 | ), 34 | migrations.RunPython(populate_slug, migrations.RunPython.noop) 35 | ] 36 | -------------------------------------------------------------------------------- /player/migrations/0008_activitylog.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.6 on 2022-05-21 14:37 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('adventure', '0067_roomexit_hintanswer_adventure_id'), 11 | ('player', '0007_playerprofile_slug'), 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='ActivityLog', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('type', models.CharField(max_length=255)), 20 | ('value', models.IntegerField(blank=True, null=True)), 21 | ('created', models.DateTimeField(auto_now_add=True, null=True)), 22 | ('adventure', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='new_activity_log', to='adventure.adventure')), 23 | ('player', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='activity_log', to='player.player')), 24 | ], 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /player/migrations/0009_move_activity_log.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.12 on 2022-05-15 08:36 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('player', '0008_activitylog'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RunSQL('SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0'), 14 | 15 | migrations.RunSQL( 16 | 'REPLACE INTO eamon.player_activitylog ' 17 | '(id, `type`, value, created, adventure_id, player_id) ' 18 | ' SELECT id, `type`, value, created, adventure_id, player_id ' 19 | ' FROM adventure_activitylog'), 20 | 21 | migrations.RunSQL('SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS') 22 | ] 23 | -------------------------------------------------------------------------------- /player/migrations/0010_alter_savedgame_player.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.12 on 2022-05-15 08:52 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('player', '0009_move_activity_log'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterField( 15 | model_name='savedgame', 16 | name='player', 17 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='saved_games', to='player.player'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /player/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/player/migrations/__init__.py -------------------------------------------------------------------------------- /player/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url, include 2 | from rest_framework import routers 3 | 4 | from .views import LogViewSet, PlayerViewSet, PlayerProfileViewSet, RatingViewSet, SavedGameViewSet 5 | 6 | # Note: This file is not currently used. See /adventure/urls.py 7 | 8 | router = routers.DefaultRouter(trailing_slash=False) 9 | router.register(r'players', PlayerViewSet) 10 | router.register(r'profiles', PlayerProfileViewSet) 11 | router.register(r'saves', SavedGameViewSet) 12 | router.register(r'ratings', RatingViewSet) 13 | router.register(r'log', LogViewSet) 14 | 15 | urlpatterns = [ 16 | # REST API routes 17 | url(r'^api/player', include(router.urls)), 18 | ] 19 | -------------------------------------------------------------------------------- /sample_import/effects.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "text": "this is sample text" 5 | }, 6 | { 7 | "id": 2, 8 | "text": "this is sample text" 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdechant/eamon/3c39dfea70cc7b71d1bc42b21df4e6f586383d34/static/.gitkeep -------------------------------------------------------------------------------- /truncate.sql: -------------------------------------------------------------------------------- 1 | SET FOREIGN_KEY_CHECKS = 0; 2 | TRUNCATE `adventure_adventure`; 3 | TRUNCATE `adventure_artifact`; 4 | TRUNCATE `adventure_artifactmarking`; 5 | TRUNCATE `adventure_effect`; 6 | TRUNCATE `adventure_monster`; 7 | TRUNCATE `adventure_room`; 8 | SET FOREIGN_KEY_CHECKS = 1; --------------------------------------------------------------------------------