Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EldritchEchos #98

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file added EldritchEchoes/bg/bg1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added EldritchEchoes/bg/bg3.avif
Binary file not shown.
429 changes: 429 additions & 0 deletions EldritchEchoes/cosmic-shadows-single-file.py

Large diffs are not rendered by default.

77 changes: 77 additions & 0 deletions EldritchEchoes/eldritch-echoes-game-description.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# EldritchEchoes: A Cosmic Horror Adventure

## Game Overview
EldritchEchoes is a text-based adventure game set in the nightmarish city of R'lyeh, a place of cosmic horror and mind-bending impossibilities. Players explore this alien landscape, facing sanity-threatening events and encounters while trying to uncover the mysteries of the city and survive the presence of the Great Old One.

## Setting: The City of R'lyeh

R'lyeh is a nightmarish metropolis of impossible geometry, rising from an endless, dark ocean. Colossal spires of alien architecture pierce the sky, their surfaces slick with an otherworldly sheen. The city seems to shift and breathe, defying the laws of physics and sanity alike.

### Key Locations

1. The Dreaming Spires: Impossibly tall towers that sway and whisper in an unfelt wind.
2. The Sunken Plaza: A vast square where the laws of gravity fluctuate unpredictably.
3. The Cyclopean Gate: A massive archway that sometimes opens to other dimensions.
4. The Whispering Library: A maze-like collection of alien tomes and artifacts.
5. The Abyss: The dark waters surrounding the city, home to unspeakable horrors.

### Atmospheric Elements

1. Perpetual Eclipse: A sickly green moon, eternally eclipsed, casts an eerie glow over the landscape.
2. Reality Distortions: Objects and buildings occasionally phase in and out of existence.
3. Psychic Whispers: Visitors to the city are plagued by maddening whispers and visions.
4. Flying Horrors: Bat-like creatures with too many wings circle the spires endlessly.

## The Great Old One

Looming over the city is a colossal entity, part octopus, part dragon, and part human, yet wholly alien. Its wings block out the sky, its tentacles weave through the city's architecture. Its presence alone is enough to shatter minds and warp reality.

## Game Mechanics

### Player Statistics

1. Sanity: Represents the player's mental health. Decreases when encountering horrors or making certain choices. If it reaches zero, the player's mind shatters.
2. Reality Anchor: Represents the player's connection to their own reality. As it decreases, they risk being lost in the alien dimension.
3. Inventory: Players can collect and use items found throughout the city.
4. Skills: Players can develop skills like "Eldritch Knowledge" and "Mental Fortitude" as they progress.

### Gameplay Elements

1. Exploration: Players navigate between different locations in R'lyeh, each with its unique descriptions and events.
2. Events: Each location has random events that the player must respond to, with choices affecting their stats and progression.
3. Item Usage: Players can find and use items that affect their stats or provide special abilities.
4. Skill Development: As players make certain choices or use certain items, their skills improve, providing benefits in future encounters.
5. Encounters with the Great Old One: Random encounters with the cosmic entity can cause significant sanity and reality anchor loss.

### Items

1. Ethereal Feather: Found in the Dreaming Spires, restores Reality Anchor when used.
2. Gravity Crystal: Found in the Sunken Plaza, restores Sanity when used.
3. Dimensional Key: Found at the Cyclopean Gate, increases Eldritch Knowledge when used.
4. Tome of Madness: Found in the Whispering Library, decreases Sanity but increases Mental Fortitude when used.

## Narrative Elements

1. The Cult of the Dreaming God: A group of humans working to fully awaken the Great Old One.
2. Ancient Artifacts: Scattered items that can grant cosmic power or insight at the cost of sanity.
3. Time Loops: Areas where time behaves erratically, trapping explorers in repeating cycles.

## Game Progression

As players explore R'lyeh, they will:
1. Discover the nature of the city and its connection to the Great Old One.
2. Uncover the plans of the Cult of the Dreaming God.
3. Find and use ancient artifacts to gain power and knowledge.
4. Navigate the dangers of the city while managing their sanity and reality anchor.
5. Eventually face a final confrontation or revelation that determines their fate.

## End Game Scenarios

1. Banishment: Find a way to send the Great Old One back to its slumber.
2. Ascension: Join with the cosmic forces and transcend humanity.
3. Escape: Discover a way to leave R'lyeh and return to the normal world.
4. Madness: Lose all sanity and become one with the horrors of R'lyeh.
5. Untethered: Lose all reality anchor and fade from existence.

This text-based adventure combines elements of exploration, resource management, and decision-making, all set against a backdrop of cosmic horror inspired by H.P. Lovecraft's works. The game challenges players to navigate the thin line between enlightenment and madness as they uncover the secrets of R'lyeh and confront forces beyond human comprehension.

Binary file not shown.
Binary file added EldritchEchoes/librarian/lib.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added EldritchEchoes/player/p1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added EldritchEchoes/portal/portal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
12 changes: 12 additions & 0 deletions EldritchEchoes/shadowssss/assets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

# File: assets.py

import pygame

def load_assets():
return {
'player_image': pygame.Surface((32, 32)), # Placeholder, replace with actual image loading
'npc_image': pygame.Surface((32, 32)), # Placeholder, replace with actual image loading
'dialogue_bg': pygame.Surface((700, 150)) # Placeholder, replace with actual image loading
}

34 changes: 34 additions & 0 deletions EldritchEchoes/shadowssss/dialogue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# File: dialogue.py

import pygame

class DialogueSystem:
def __init__(self, background_image):
self.background = background_image
self.dialogues = {
"Detective": [
"Welcome to Shadowbrook. I'm Detective Johnson.",
"We've been experiencing some strange occurrences lately.",
"I hope you can help us get to the bottom of this mystery."
]
}
self.current_npc = None
self.dialogue_index = 0

def start_dialogue(self, npc_name):
self.current_npc = npc_name
self.dialogue_index = 0
return self.dialogues[npc_name][self.dialogue_index]

def next(self):
self.dialogue_index += 1
if self.dialogue_index < len(self.dialogues[self.current_npc]):
return self.dialogues[self.current_npc][self.dialogue_index]
else:
return None

def draw(self, screen, current_dialogue):
screen.blit(self.background, (50, 400))
font = pygame.font.Font(None, 28)
text = font.render(current_dialogue, True, (255, 255, 255))
screen.blit(text, (60, 410))
116 changes: 116 additions & 0 deletions EldritchEchoes/shadowssss/game.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# File: game.py

import pygame
from player import Player
from npc import NPC
from puzzle import Puzzle
from dialogue import DialogueSystem
import json

class GameState:
MENU = 0
PLAYING = 1
DIALOGUE = 2
PUZZLE = 3
INVENTORY = 4

class CosmicShadows:
def __init__(self, screen, assets):
self.screen = screen
self.assets = assets
self.state = GameState.MENU
self.player = Player(400, 300, assets['player_image'])
self.npcs = [NPC(200, 200, assets['npc_image'], "Detective")]
self.puzzles = [Puzzle("Decrypt the ancient tome", "ELDRITCHHORROR", "Unscramble the letters")]
self.dialogue_system = DialogueSystem(assets['dialogue_bg'])
self.current_dialogue = None
self.sanity_drain_rate = 1 # Sanity points lost per second
self.load_game()

def handle_event(self, event):
if self.state == GameState.PLAYING:
self.player.handle_event(event)
elif self.state == GameState.DIALOGUE:
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
self.current_dialogue = self.dialogue_system.next()
if self.current_dialogue is None:
self.state = GameState.PLAYING
elif self.state == GameState.PUZZLE:
if event.type == pygame.KEYDOWN:
self.puzzles[0].input_letter(event.unicode)

def update(self, dt):
if self.state == GameState.PLAYING:
self.player.update(dt)
self.update_sanity(dt)
self.check_npc_interactions()
elif self.state == GameState.PUZZLE:
if self.puzzles[0].is_solved():
self.state = GameState.PLAYING
self.player.knowledge += 1

def draw(self):
self.screen.fill((0, 0, 0)) # Black background

if self.state == GameState.PLAYING:
self.player.draw(self.screen)
for npc in self.npcs:
npc.draw(self.screen)
elif self.state == GameState.DIALOGUE:
self.dialogue_system.draw(self.screen, self.current_dialogue)
elif self.state == GameState.PUZZLE:
self.puzzles[0].draw(self.screen)

# Draw sanity meter
pygame.draw.rect(self.screen, (255, 0, 0), (10, 10, self.player.sanity * 2, 20))

pygame.display.flip()

def update_sanity(self, dt):
self.player.sanity -= self.sanity_drain_rate * dt
if self.player.sanity <= 0:
self.game_over()

def check_npc_interactions(self):
for npc in self.npcs:
if self.player.rect.colliderect(npc.rect):
self.start_dialogue(npc)

def start_dialogue(self, npc):
self.state = GameState.DIALOGUE
self.current_dialogue = self.dialogue_system.start_dialogue(npc.name)

def game_over(self):
print("Game Over - Sanity depleted")
self.save_game()
pygame.quit()
sys.exit()

def save_game(self):
game_state = {
"player": {
"x": self.player.rect.x,
"y": self.player.rect.y,
"sanity": self.player.sanity,
"inventory": self.player.inventory,
"knowledge": self.player.knowledge
},
"npcs": [{"x": npc.rect.x, "y": npc.rect.y, "name": npc.name} for npc in self.npcs],
"puzzles": [puzzle.to_dict() for puzzle in self.puzzles]
}
with open("savegame.json", "w") as f:
json.dump(game_state, f)

def load_game(self):
try:
with open("savegame.json", "r") as f:
game_state = json.load(f)
self.player.rect.x = game_state["player"]["x"]
self.player.rect.y = game_state["player"]["y"]
self.player.sanity = game_state["player"]["sanity"]
self.player.inventory = game_state["player"]["inventory"]
self.player.knowledge = game_state["player"]["knowledge"]
self.npcs = [NPC(npc["x"], npc["y"], self.assets['npc_image'], npc["name"]) for npc in game_state["npcs"]]
self.puzzles = [Puzzle.from_dict(puzzle_dict) for puzzle_dict in game_state["puzzles"]]
except FileNotFoundError:
print("No save game found. Starting new game.")
41 changes: 41 additions & 0 deletions EldritchEchoes/shadowssss/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# File: main.py

import pygame
import sys
from game import CosmicShadows
from assets import load_assets

# Initialize Pygame
pygame.init()

# Set up the display
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Cosmic Shadows")

# Load assets
assets = load_assets()

def main():
clock = pygame.time.Clock()
game = CosmicShadows(screen, assets)

running = True
while running:
dt = clock.tick(60) / 1000 # Delta time in seconds

for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
game.handle_event(event)

game.update(dt)
game.draw()

pygame.display.flip()

pygame.quit()
sys.exit()

if __name__ == "__main__":
main()
12 changes: 12 additions & 0 deletions EldritchEchoes/shadowssss/npc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# File: npc.py

import pygame

class NPC:
def __init__(self, x, y, image, name):
self.rect = pygame.Rect(x, y, 32, 32)
self.image = image
self.name = name

def draw(self, screen):
screen.blit(self.image, self.rect)
25 changes: 25 additions & 0 deletions EldritchEchoes/shadowssss/player.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# File: player.py

import pygame

class Player:
def __init__(self, x, y, image):
self.rect = pygame.Rect(x, y, 32, 32)
self.image = image
self.speed = 5
self.sanity = 100
self.inventory = []
self.knowledge = 0

def handle_event(self, event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_i:
print(f"Inventory: {self.inventory}")

def update(self, dt):
keys = pygame.key.get_pressed()
self.rect.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * self.speed
self.rect.y += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * self.speed

def draw(self, screen):
screen.blit(self.image, self.rect)
39 changes: 39 additions & 0 deletions EldritchEchoes/shadowssss/puzzle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# File: puzzle.py

import pygame

class Puzzle:
def __init__(self, name, solution, clue):
self.name = name
self.solution = solution
self.clue = clue
self.current_input = ""

def input_letter(self, letter):
self.current_input += letter
if len(self.current_input) > len(self.solution):
self.current_input = self.current_input[1:]

def is_solved(self):
return self.current_input.lower() == self.solution.lower()

def draw(self, screen):
font = pygame.font.Font(None, 36)
clue_text = font.render(self.clue, True, (255, 255, 255))
input_text = font.render(self.current_input, True, (255, 255, 255))
screen.blit(clue_text, (100, 100))
screen.blit(input_text, (100, 150))

def to_dict(self):
return {
"name": self.name,
"solution": self.solution,
"clue": self.clue,
"current_input": self.current_input
}

@classmethod
def from_dict(cls, data):
puzzle = cls(data["name"], data["solution"], data["clue"])
puzzle.current_input = data["current_input"]
return puzzle