From 2173733463e9e73f325b1c5818fd5ec683483dc9 Mon Sep 17 00:00:00 2001
From: Zachary Watts
Date: Sat, 2 May 2026 00:41:49 -0400
Subject: [PATCH] cleaning up app and improving html
---
README.md | 23 ++++++++++++++++--
app.py | 52 +++++++++++++++++++---------------------
main.py | 9 ++-----
templates/character.html | 8 +++++--
templates/party.html | 3 ---
5 files changed, 53 insertions(+), 42 deletions(-)
diff --git a/README.md b/README.md
index da9e905..fbcca8d 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,22 @@
-# ose-character-gen
+# OSE Character Generator
-Web app for old school D&D character generation
\ No newline at end of file
+This tool uses the Old School Essentials (OSE) ruleset for tabletop RPGs in order to randomly generate a character.
+
+### What is Dungeons & Dragons?
+Dungeons & Dragons, also known as D&D, is a pen and paper table top game. One player is the story teller, the "dungeon master" and the others interact with the story using their "adventurers." An adventurer is a playable character, who has a mixture of abilities and powers, the details of which are often kept on piece of paper called a "character sheet."
+
+### How does the game work?
+Most settings are fantasy based, like game of thrones or lord of the rings. Players often pick up a quest in one of these fantasy worlds, guided by the "Dungeon Master" who narrates the world. The players will make decisions, take actions, and ultimate help write the story as it unfolds.
+
+### Why would I need a character generator?
+It takes time and effort to create a new character; there are many rules, phrases, and terminology you'll need to know to create a character. Most rule books provide an easy to follow guide on making player characters or "adventurers." However, if you are short on time, a generator such as this will get you in the game right away!
+
+### About This App
+This app accomplishes a few things, but mainly it creates a character for you.
+
+- It follows the rules precisely from the books to generate a legal character
+- All stats are randomly rolled, but a class is chosen per your best stats
+- Character equipment and spells are also randomly selected, within that character-class rules
+- You can generate a whole party of characters
+- Within that party, you can adjust their level, and the number of characters
+- You can create a single character to edit
diff --git a/app.py b/app.py
index fc7d380..41e8829 100644
--- a/app.py
+++ b/app.py
@@ -7,47 +7,53 @@ from flask_session import Session
app = Flask(__name__)
-# Configure session
-app.config["SESSION_PERMANENT"] = False
-app.config["SESSION_TYPE"] = "filesystem"
-Session(app)
+# useful functions
+def compress_character(adventurer):
+ cookie_string = adventurer.identifier
+ adventurer_json = json.dumps(adventurer.get_json())
+ compressed_data = zlib.compress(adventurer_json.encode())
+ cookie_data = base64.urlsafe_b64encode(compressed_data).decode()
+ return cookie_string, cookie_data
+def return_character_from_cookie(cookie):
+ cookie_decompressed = base64.urlsafe_b64decode(cookie)
+ adventurer_dict = json.loads(zlib.decompress(cookie_decompressed).decode())
+ adventurer = createCharacterWithDict(adventurer_dict)
+ return adventurer
@app.route('/')
def index():
tab = request.args.get("tab", default="what", type=str)
+ # control argument inputs to tabs available on index.html
if tab not in [ "what", "how", "why", "about" ]:
tab = "what"
return render_template("index.html", tab=tab)
@app.route('/party', methods = ["GET"])
def party():
- print("generating party")
+ # default values, modified if cookies exist
stored_adv_party = []
stored_count = None
stored_level = None
if request.method == "GET":
- print('in get if')
count = request.args.get("count", default=4, type=int)
level = request.args.get("level", default=1, type=int)
cache = request.args.get("cache", default='true', type=str)
+ # control inputs to prevent abuse
if cache not in [ "true", "false" ]:
cache = 'true'
if level < 1 or level > 5:
level = 1
if count < 2 or count > 5:
count = 4
+ # generate an adventuring party
adv_party = returnParty(count, level)
# check for cookies present
if request.cookies:
stored_count = len(request.cookies)
- #print(request.cookies)
for c in request.cookies:
if c.startswith('adv'):
- cookie_encoded = request.cookies[c]
- cookie_compressed = base64.urlsafe_b64decode(cookie_encoded)
- character_dict = json.loads(zlib.decompress(cookie_compressed).decode())
- new_char = createCharacterWithDict(character_dict)
+ new_char = return_character_from_cookie(request.cookies[c])
stored_level = new_char.level
stored_adv_party.append(new_char)
# if request arguments match the adventure party count & level stored in the cookies, just use the cookies
@@ -68,14 +74,9 @@ def party():
adv_party.set_party(reduced_party, count, level)
# generate page
response = make_response(render_template("party.html", adv_party=adv_party, count=count, level=level, cache=cache))
- print(response)
# make a cookie for each character
- # this took a while to figure out, json was too large, b64 encoded json was too large, but it turns out you can compress json as a cookie
- for character in adv_party.adventurers:
- cookie_string = character.identifier
- char_json = json.dumps(character.get_json())
- compressed = zlib.compress(char_json.encode())
- cookie_data = base64.urlsafe_b64encode(compressed).decode()
+ for adv in adv_party.adventurers:
+ cookie_string, cookie_data = compress_character(adv)
response.set_cookie(cookie_string, cookie_data)
return response
@@ -95,19 +96,17 @@ def character():
if role not in [ 'fighter','magic-user','cleric', 'thief', 'dwarf', 'elf', 'halfling']:
role = 'fighter'
if request.cookies and cache != "false":
- cookie_encoded = request.cookies[c_id]
- cookie_compressed = base64.urlsafe_b64decode(cookie_encoded)
- character_dict = json.loads(zlib.decompress(cookie_compressed).decode())
- character = createCharacterWithDict(character_dict)
+ character = return_character_from_cookie(request.cookies[c_id])
+ print(character.player_class)
if character.level != level:
character.set_level(level)
# reroll until we get our class
while character.player_class != role.replace("-"," "):
- new_char = Adventurer(c_id, 1)
+ new_char = Adventurer(c_id, level)
selected_class = ClassSelector(new_char).selection()
character = selected_class(new_char.identifier, new_char.level, new_char.get_attributes())
else:
- new_char = Adventurer(c_id, 1)
+ new_char = Adventurer(c_id, level)
selected_class = ClassSelector(new_char).selection()
character = selected_class(new_char.identifier, new_char.level, new_char.get_attributes())
role = character.player_class
@@ -116,9 +115,6 @@ def character():
if character.player_class == "cleric":
character.turn_undead = { int(k) : v for k,v in character.turn_undead.items() }
response = make_response(render_template("character.html", character=character, level=level, cache=cache,role=role))
- cookie_string = character.identifier
- char_json = json.dumps(character.get_json())
- compressed = zlib.compress(char_json.encode())
- cookie_data = base64.urlsafe_b64encode(compressed).decode()
+ cookie_string, cookie_data = compress_character(character)
response.set_cookie(cookie_string, cookie_data)
return response
diff --git a/main.py b/main.py
index 7f15769..ea68d61 100755
--- a/main.py
+++ b/main.py
@@ -105,7 +105,7 @@ def returnCharacter(identifer):
if adv.identifier == identifier:
return adv
-def createCharacterWithDict(character_dict):
+def createCharacterWithDict(character_dict) -> Adventurer:
chosen_class = character_dict['player_class']
c_id = character_dict['identifier']
level = character_dict['level']
@@ -116,13 +116,8 @@ def createCharacterWithDict(character_dict):
setattr(new_char,k, v)
return new_char
-
+# used for local testing
def main():
- #adventurer_party = returnParty(party_size=2, party_level=2)
- #for adv in adventurer_party.adventurers:
- # print(adv.adv_class, adv.level)
- # adv.set_level(10)
- # print(adv.adv_class, adv.level)
adv_dict = Adventurer.get_subclass_dict()
test_class = adv_dict['cleric']
new_char = test_class(c_id="adv-1",level=2)
diff --git a/templates/character.html b/templates/character.html
index 57e121e..b514e39 100644
--- a/templates/character.html
+++ b/templates/character.html
@@ -36,6 +36,9 @@
+
Character Generator
+
The below lets you generate a character based on your preferences. If you change levels, there will be subtle changes, usually just the "saving throws" and "hp" will change. Some classes, like spellcasters, will gain new spells.