cleaning up app and improving html
This commit is contained in:
23
README.md
23
README.md
@@ -1,3 +1,22 @@
|
||||
# ose-character-gen
|
||||
# OSE Character Generator
|
||||
|
||||
Web app for old school D&D character generation
|
||||
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.</p>
|
||||
|
||||
### 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
|
||||
|
||||
52
app.py
52
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
|
||||
|
||||
9
main.py
9
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)
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
<div class="content">
|
||||
<div class="block">
|
||||
<div class="block">
|
||||
<h1>Character Generator</h1>
|
||||
<p>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.</p>
|
||||
<hr>
|
||||
<div class="columns">
|
||||
<div class="column" >
|
||||
<p>Select a Class</p>
|
||||
@@ -81,6 +84,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="card">
|
||||
<h3>{{character.adv_class.title()}} - Level {{character.level}}</h3>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
@@ -114,9 +119,8 @@
|
||||
</div>
|
||||
{% if character.spells %}
|
||||
<div class="column">
|
||||
<h5>Spellbook</h5>
|
||||
<table class="table">
|
||||
<thead><tr><th>Spellname</th><th></th><th></th><th></th></thead>
|
||||
<thead><tr><th>Spellbook</th><th></th><th></th><th></th></thead>
|
||||
{%for spell in character.spell_book %}
|
||||
<tbody><tr><th>{{spell}}</th><td></td><th></th><td></td></tr></tbody>
|
||||
{%endfor%}
|
||||
|
||||
@@ -90,9 +90,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="block has-text-centered">
|
||||
<button class="button is-primary is-fillwidth">Select this adventuring party!</button>
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user