I’m making a text-based rpg right now, and I have just gotten completely stumped from my main menu quit option just completely not working, and I cannot find a single reason why, I slammed it into chatgpt like 20 times to see if it could find the issue, and it said its unusual. It also specifically happens after you’ve gone through a battle atleast one time, but when you have yet to play the game once, it quits as intended. Also probably worth noting is that this is using the default python from replit.com
the loading_screen() function referenced in the main menu just uses the time.sleep() function to do a “…” after you enter the parameter for a quote
loading_screen() function, in case it finds itself being a problem
def loading_screen(seconds, quote):
print(quote, end="", flush=True)
for _ in range(seconds):
time.sleep(0.5)
print(".", end="", flush=True)
print()
savegame() function
def savegame():
global damageThisBattle
global itemsUsed
global playerExperience
global experienceToNextLevel
global currentLevel
global ogresKilled
global skeletonsKilled
saveFile = open("savestates.txt", "r+")
lines = saveFile.readlines()
saveFile.seek(0)
# Move the cursor to the beginning of the file
ogresKilled = ogresKilled + int(lines[0].strip())
skeletonsKilled = skeletonsKilled + int(lines[1].strip())
totalDamage = int(lines[2].strip()) + damageThisBattle
totalItemsUsed = int(lines[3].strip()) + itemsUsed
# Update the lines with the new values
saveFile.write(str(ogresKilled) + "\n")
saveFile.write(str(skeletonsKilled) + "\n")
saveFile.write(str(totalDamage) + "\n")
saveFile.write(str(totalItemsUsed) + "\n")
saveFile.write(str(currentExperience) + "\n")
saveFile.write(str(currentLevel) + "\n")
# Truncate the file in case the new content is smaller
# than the old content
saveFile.truncate()
saveFile.close()
Main menu code ran in a loop where the other condition is (if inBattle == True:)
while playInput not in validPlayInputs:
printMainMenu()
playInput=input("\n1. Play\n2. Check Save\n3. Wipe save"
"\n4. Quit\n")
if playInput=="1":
loadgame()
if newGame==False:
loading_screen(3,"Loading Save")
loading_screen(3,"Starting game")
print("")
print("")
else:
loading_screen(3,"Starting New Game")
elif playInput=="2":
checkSave()
elif playInput=="3":
wipeSave()
elif playInput=="4":
loading_screen(3,"Quitting")
os._exit(0)
The entire code itself:
import random
import math
import sys
import subprocess
import time
import os
def restart_program():
python = sys.executable
subprocess.call([python] + sys.argv)
# Lots of variables
quit_game=False
inBattle=False
experienceToNextLevel=0
currentExperience=0
experienceDefault=30
currentLevel=0
levelMultiplier=1.3
ogresKilled=0
skeletonsKilled=0
newGame=False
lineNo=0
turnCount=1
backToSelection=False
actionInput=""
skillInput=""
weaponSelect=""
itemUse=""
itemsUsed=0
totalItemsUsed=0
totalDamage=0
damageThisBattle=0
playInput=""
areaSelect=""
saveGameInput=""
validSaveInputs=["Y","N"]
turnsOnFire=0
playerHealth=20
playerMaxHealth=20
playerMana=10
playerMaxMana=10
playerExperience=0
battleExperience=0
deathPrompt="You died!"
missPrompt="The attack missed!"
# Enemy Stat Variables
enemy_type=""
enemyDamage=0
enemyHealth=0
enemyMaxHealth=0
enemyHealthBarFilled=0
specificAttack=0
attackPrompt1,attackPrompt2="",""
attack1Low,attack1High=0,0
attack2Low,attack2High=0,0
enemyOnFire=False
enemyDefeated=True
enemyKillsThisBattle=0
playerExperience=""
#
weaponDamage=0
weaponAccuracy=0
skillAccuracy=0
playerAttack=0
defended=False
validCommands=["1","SKILL","2","GUARD","3","ITEM","4","RUN"]
validItemCommands=["1","HEALTH","2","MANA","3"]
validWeaponCommands=["1","2","3","4"]
validPlayInputs=["1","3"]
validSkillCommands=["1","2","3","4","5"]
validAreas=["1","2","FOREST","DESERT"]
healthPotions=2
manaPotions=1
seconds=0
quote=""
area=""
# Dictionaries for data storage and calling
# The Chance of the attack is added up from the previous num to 100,
# So if attack 1 goes from 0 to 80 its an 80% chance of happening,
# And attack 2 goes from 81 to 100 its a 20% chance of happening
enemy_types = {
"Ogre": {
"attack_prompt1": "The Ogre swings his club at you!",
"attack_prompt2": "The Ogre charges at you!",
"attack1_accuracy": 90,
"attack2_accuracy": 60,
"attack1_damageRange": (4, 6),
"attack2_damageRange": (4, 8),
"attack1_chance": 80,
"attack2_chance": 81,
"max_health": 20,
"Experience_reward": 15},
"Skeleton": {
"attack_prompt1": "The Skeleton swings his sword at you!",
"attack_prompt2": "The Skeleton tries to deal a devastating strike!",
"attack1_accuracy": 85,
"attack2_accuracy": 25,
"attack1_damageRange": (7,9),
"attack2_damageRange": (10,15),
"attack1_chance": 90,
"attack2_chance": 91,
"max_health": 35,
"Experience_reward": 40}
}
# Defining of functions
# Experience functions
def calculateExperienceRequired():
global levelMultiplier
global currentLevel
global currentExperience
global experienceDefault
return int(experienceDefault * (levelMultiplier ** currentLevel))
def currentPlayerLevel():
global currentLevel
global currentExperience
global battleExperience
global experienceToNextLevel
currentExperience+=battleExperience
while currentExperience >= calculateExperienceRequired():
currentExperience=currentExperience - calculateExperienceRequired()
currentLevel+=1
print(f"You leveled up to level {currentLevel}!")
battleExperience=0
experienceToNextLevel=calculateExperienceRequired()-currentExperience
def currentPlayerLevelDebug():
global currentLevel
global currentExperience
global battleExperience
print("current experience:",currentExperience)
currentExperience+=battleExperience
print("current experience:",currentExperience)
if currentExperience >= calculateExperienceRequired():
print("current level",currentLevel)
currentLevel+=1
print("You leveled up to level:",currentLevel)
print("current level",currentLevel)
currentExperience=currentExperience%calculateExperienceRequired()
print("current experience:",currentExperience)
# Loading screen function, quitting screen, rebooting screen, etc...
def loading_screen(seconds, quote):
print(quote, end="", flush=True)
for _ in range(seconds):
time.sleep(0.5)
print(".", end="", flush=True)
print()
# Check save function
def checkSave():
try:
loading_screen(3,"Checking save")
saveFile = open("savestates.txt", "r")
lines = saveFile.readlines()
if len(lines) >= 6 and all(line.strip().isdigit() for line in lines):
print("Save data found.")
print("Total Ogres defeated:", lines[0])
print("Total Skeletons defeated:", lines[1])
print("Total damage dealt:", lines[2])
print("Total items used:", lines[3])
print("Experience:", lines[4])
print("Level:", lines[5])
else:
loading_screen(3,"Invalid format, initializing save file")
saveFile = open("savestates.txt", "w")
saveFile.write("0\n0\n0\n0\n0\n0")
saveFile.close()
print("Save file initialized.")
except Exception as e:
print("Error:", e)
finally:
saveFile.close()
# Wipe save function
def wipeSave():
saveFile=open("savestates.txt","w")
saveFile.write("0\n0\n0\n0\n0\n0")
loading_screen(3,"Rebooting")
saveFile.close()
restart_program()
# Saving function
def savegame():
global damageThisBattle
global itemsUsed
global playerExperience
global experienceToNextLevel
global currentLevel
global ogresKilled
global skeletonsKilled
saveFile = open("savestates.txt", "r+")
lines = saveFile.readlines()
saveFile.seek(0)
# Move the cursor to the beginning of the file
ogresKilled = ogresKilled + int(lines[0].strip())
skeletonsKilled = skeletonsKilled + int(lines[1].strip())
totalDamage = int(lines[2].strip()) + damageThisBattle
totalItemsUsed = int(lines[3].strip()) + itemsUsed
# Update the lines with the new values
saveFile.write(str(ogresKilled) + "\n")
saveFile.write(str(skeletonsKilled) + "\n")
saveFile.write(str(totalDamage) + "\n")
saveFile.write(str(totalItemsUsed) + "\n")
saveFile.write(str(currentExperience) + "\n")
saveFile.write(str(currentLevel) + "\n")
# Truncate the file in case the new content is smaller
# than the old content
saveFile.truncate()
saveFile.close()
# Loading Function
def loadgame():
global playerExperience
global currentLevel
global newGame
global experienceToNextLevel
global currentExperience
try:
saveFile = open("savestates.txt", "r")
lines = saveFile.readlines()
if len(lines) >= 6 and all(value.strip().isdigit() and int(value.strip()) \
== 0 for value in lines):
print("New save detected!")
currentLevel+=1
newGame=True
elif len(lines) >= 6 and all(value.strip().isdigit() for value in lines[:6]):
print("Save File Found!")
newGame=False
currentExperience = int(lines[4].strip())
currentLevel = int(lines[5].strip())
saveFile.close()
except Exception as e:
print("No save detected, creating new save file.")
# Player Statistic Initialization based on level
def playerStats():
global playerMaxHealth
global playerHealth
global playerMaxMana
global playerMana
global weaponDamage
playerMaxHealth=(currentLevel-1)*3+20
playerHealth=playerMaxHealth
playerMaxMana=(currentLevel-1)*2+10
playerMana=playerMaxMana
weaponDamage=math.ceil(weaponDamage+(weaponDamage*currentLevel-1)*0.1)
# Enemy Type Finding for Statistic Updates
def enemyTypeKilled():
global enemy_type
global ogresKilled
global skeletonsKilled
if enemy_type == "Ogre":
ogresKilled+=1
elif enemy_type == "Skeleton":
skeletonsKilled+=1
# Enemy Initialization Upon Choosing Area
def initializeEnemy(area):
global enemy_type, enemyMaxHealth, enemyHealth, enemy_types
if area == "Forest":
enemy_type = "Ogre"
elif area == "Desert":
enemy_type = "Skeleton"
enemyMaxHealth = enemy_types[enemy_type]["max_health"]
enemyHealth = enemyMaxHealth
# enemyAttack(s) function(s)
def enemyAttack(playerHealth,defended,enemy_type):
attackPrompt1 = enemy_types[enemy_type]["attack_prompt1"]
attackPrompt2 = enemy_types[enemy_type]["attack_prompt2"]
attack1Accuracy = enemy_types[enemy_type]["attack1_accuracy"]
attack2Accuracy = enemy_types[enemy_type]["attack2_accuracy"]
attack1Low, attack1High = enemy_types[enemy_type]["attack1_damageRange"]
attack2Low, attack2High = enemy_types[enemy_type]["attack2_damageRange"]
attack1Chance = enemy_types[enemy_type]["attack1_chance"]
attack2Chance = enemy_types[enemy_type]["attack2_chance"]
if playerHealth<=0:
print(deathPrompt)
specificAttack=random.randint(1,100)
if specificAttack<=attack1Chance:
print(attackPrompt1)
if random.randint(1,100)<=attack1Accuracy:
enemyDamage=random.randint(attack1Low,attack1High)
if defended==True:
enemyDamage=math.ceil(enemyDamage/2)
print("Damage taken:",enemyDamage)
playerHealth=playerHealth-enemyDamage
else:
print(missPrompt)
elif specificAttack>=attack2Chance:
print(attackPrompt2)
if random.randint(1,100)<=attack2Accuracy:
enemyDamage=random.randint(attack1Low,attack2High)
if defended==True:
enemyDamage=math.ceil(enemyDamage/2)
playerHealth=playerHealth-enemyDamage
print("Damage taken:",enemyDamage)
else:
print(missPrompt)
return playerHealth
# Main Menu Function
def printMainMenu():
print("╔══════════════════════════════════════╗\n"
"║ Epic Battle Simulator ║\n"
"╚══════════════════════════════════════╝")
# Player Status Bars Function
def playerStatusBars():
global playerHealth
global playerMaxHealth
global playerMaxMana
global playerMana
global currentExperience
global experienceToNextLevel
playerHealthRatio = playerHealth / playerMaxHealth
playerManaRatio = playerMana / playerMaxMana
try:
playerExpRatio=currentExperience / calculateExperienceRequired()
except ZeroDivisionError:
playerExpRatio=0
barLength = 20
healthBarFilled = int(barLength * playerHealthRatio)
manaBarFilled = int(barLength * playerManaRatio)
expBarFilled= int(barLength*playerExpRatio)
healthBar = "[" + "■" * healthBarFilled + " " * (barLength - healthBarFilled) + "]"
manaBar = "[" + "■" * manaBarFilled + " " * (barLength - manaBarFilled) + "]"
expBar = "[" + "■" * expBarFilled + " " * (barLength - expBarFilled) + "]"
print(f"Health: {healthBar} {playerHealth}/{playerMaxHealth}")
print(f" Mana: {manaBar} {playerMana}/{playerMaxMana}")
print(f" Exp: {expBar} {currentExperience}/{calculateExperienceRequired()}")
# Enemy Status Bar Function
def enemyStatusBar(enemyHealth, enemyMaxHealth):
enemyHealthRatio = enemyHealth / enemyMaxHealth
barLength = 20
enemyHealthBarFilled = int(barLength * enemyHealthRatio)
enemyHealthBar = "[" + "■" * enemyHealthBarFilled + " " * (barLength - enemyHealthBarFilled) + "]"
print(f"Enemy: {enemyHealthBar} {enemy_type}")
###########################
# Game Loop
###########################
while True:
if quit_game:
loading_screen(3, "Quitting")
sys.exit()
while inBattle==True:
if playInput=="4":
sys.exit()
actionInput=""
defended=False
backToSelection=False
print("--------------")
print("Current turn: %d" % turnCount)
enemyStatusBar(enemyHealth,enemyMaxHealth)
playerStatusBars()
print("--------------")
while actionInput not in validCommands:
actionInput=input("1. Skill\n2. Guard\n3. Item\n4. Run\n--------------\n")
if actionInput not in validCommands:
print("Valid Commands =", validCommands)
# Function 1: Skill
skillInput=""
if actionInput.upper()=="SKILL" or actionInput.upper()=="1":
while skillInput not in validSkillCommands or skillInput=="4":
skillInput=input("--------------\n"
"1. Basic attack M:0\n2. Strong attack M:5\n3. Blazing "
"Slash M:10\n4. Attack Descriptions\n5. Back to selection"
"\n--------------\n")
if skillInput=="1":
print("--------------")
print("You attack the enemy!")
playerAttack=random.randint(weaponDamage-1,weaponDamage+1)
if random.randint(1,100)<=weaponAccuracy:
print("You hit the enemy!")
print("Damage dealt:",playerAttack)
enemyHealth=enemyHealth-playerAttack
damageThisBattle+=playerAttack
else:
print("You missed!")
playerAttack=0
if enemyHealth<0:
enemyHealth=0
elif skillInput=="2" and playerMana >=5:
if playerMana<5:
backToSelection=True
print("Not enough mana")
playerMana-=5
print("--------------")
print("You use a strong attack!")
playerAttack=random.randint(weaponDamage-1,weaponDamage+1)
if random.randint(1,100)<=weaponAccuracy:
playerAttack=math.ceil(playerAttack*1.30)
print("You hit the enemy!")
print("Damage dealt:",playerAttack)
enemyHealth=enemyHealth-playerAttack
damageThisBattle+=playerAttack
else:
print("You missed!")
playerAttack=0
if enemyHealth<0:
enemyHealth=0
elif skillInput=="3" and playerMana>=10:
if playerMana<10:
backToSelection=True
print("Not enough mana")
playerMana-=10
enemyOnFire=True
turnsOnFire=3
print("--------------")
print("You use blazing slash!")
print("Enemy now burning!")
playerAttack=random.randint(weaponDamage-1,weaponDamage+1)
playerAttack=math.ceil(playerAttack*1.25)
print("Damage dealt:",playerAttack)
enemyHealth=enemyHealth-playerAttack
damageThisBattle+=playerAttack
if enemyHealth<0:
enemyHealth=0
elif skillInput=="4":
print("Basic and Strong attacks have a chance to miss"
" based on weapon accuracy.\n--------------")
print("Basic attack: Deals damage based on your weapon damage +/- 1. Mana:0"
"\n--------------")
print("Strong attack: Deals 30% more damage,"
" rounded up, than a regular attack. Mana:5\n--------------")
print("Blazing Slash: Guaranteed hit, Deals 25% more damage,"
" rounded up, than a regular attack, and "
"lights the enemy on fire, dealing 2 damage per turn"
" for 3 turns. Mana:10"
"\n--------------")
elif skillInput=="5":
backToSelection=True
# Function 2: Guard
elif actionInput.upper()=="GUARD" or actionInput.upper()=="2":
print("You guard!")
print("You regenerated 4 mana!")
playerMana+=4
if playerMana>playerMaxMana:
playerMana=playerMaxMana
defended=True
# Function 3: Item
elif actionInput.upper()=="ITEM" or actionInput.upper()=="3":
itemUse=""
if healthPotions<=0 and manaPotions<=0:
print("You have no items remaining!")
continue
while itemUse not in validItemCommands:
itemUse=input("What item do you want to use?\n1. Health Potion (%d)"
"\n2. Mana Potion (%d)\n"
"3. Back to selection"
"\n--------------\n" % (healthPotions,manaPotions))
if itemUse.upper() in validItemCommands:
if itemUse.upper()=="1" or itemUse.upper()=="HEALTH":
if healthPotions<=0:
print("None left!")
validItemCommands.remove("1")
validItemCommands.remove("HEALTH")
continue
print("You use a health potion!")
itemsUsed+=1
playerHealth+=10
if playerHealth>playerMaxHealth:
playerHealth=playerMaxHealth
healthPotions-=1
elif itemUse.upper()=="2" or itemUse.upper()=="MANA":
if manaPotions<=0:
print("None left!")
validItemCommands.remove("2")
validItemCommands.remove("MANA")
continue
print("You use a mana potion!")
itemsUsed+=1
playerMana+=10
if playerMana>playerMaxMana:
playerMana=playerMaxMana
manaPotions-=1
elif itemUse.upper()=="3":
backToSelection=True
# Function 4: Run
elif actionInput.upper()=="RUN" or actionInput.upper()=="4":
print("Coward!")
break
# Final Statements
if backToSelection==True:
continue
turnCount+=1
if enemyOnFire==True:
enemyHealth-=2
damageThisBattle+=2
print("The enemy takes 2 fire damage!")
turnsOnFire-=1
if turnsOnFire<=0:
print("Enemy stopped burning")
enemyOnFire=False
if enemyHealth<=0:
inBattle=False
area=""
areaSelect=""
print("Enemy defeated!")
enemyDefeated=True
battleExperience=enemy_types[enemy_type]["Experience_reward"]
currentPlayerLevel()
enemyTypeKilled()
print("Turns:", turnCount)
while saveGameInput not in validSaveInputs and playInput!=4:
saveGameInput=input("Do you want to save your game? (y/n)\n")
if saveGameInput.upper()=="Y":
savegame()
loading_screen(3,"Saving and returning to main menu")
restart_program()
else:
saveGameInput=""
while saveGameInput not in validSaveInputs:
saveGameInput=input("Do you want to quit without saving? (y/n)\n")
if saveGameInput.upper()=="Y":
loading_screen(3,"Returning to main menu")
restart_program()
else:
savegame()
loading_screen(3,"Saving and returning to main menu")
restart_program()
break
else:
playerHealth=enemyAttack(playerHealth,defended,enemy_type)
if playerHealth<=0:
loading_screen(3,"You died! Returning to main menu")
restart_program()
else:
# Actual Main Menu
while playInput not in validPlayInputs:
printMainMenu()
playInput=input("\n1. Play\n2. Check Save\n3. Wipe save"
"\n4. Quit\n")
if playInput=="1":
loadgame()
if newGame==False:
loading_screen(3,"Loading Save")
loading_screen(3,"Starting game")
print("")
print("")
else:
loading_screen(3,"Starting New Game")
elif playInput=="2":
checkSave()
elif playInput=="3":
wipeSave()
elif playInput=="4":
loading_screen(3,"Quitting")
os._exit(0)
# Weapon selection prior to fight
while weaponSelect not in validWeaponCommands or weaponSelect=="4":
weaponSelect=input("--------------\nWhat weapon do you want to use?"
" \n1. Sword\n2. Greatsword\n3. Shortsword"
"\n4. Weapon stats\n--------------\n")
if weaponSelect.upper()=="1":
weaponDamage=6
weaponAccuracy=80
elif weaponSelect.upper()=="2":
weaponDamage=10
weaponAccuracy=50
elif weaponSelect.upper()=="3":
weaponDamage=5
weaponAccuracy=100
elif weaponSelect.upper()=="4":
print("Sword\n--------\nDamage: 6\nAccuracy: 80\n"
"A low risk and medium reward weapon with good accuracy and damage\n"
"Tip: A versatile weapon for any playstyle"
"\n\nGreatsword\n--------\nDamage: 10\nAccuracy: 50"
"\nA high risk high reward weapon with low accuracy and high damage\n"
"Tip: Good for powerful guaranteed hit skills"
"\n\nShortsword\n--------\nDamage: 5\nAccuracy: 100\n"
"A zero risk and low reward weapon with perfect accuracy and low damage\n"
"Tip: Good for repeated strong attacks\n")
while areaSelect not in validAreas:
areaSelect=input("--------------\nWhere do you want to go?\n"
"1. Forest\n2. Desert\n").upper()
if areaSelect == "1" or areaSelect == "FOREST":
loading_screen(3,"Entering Forest")
area="Forest"
inBattle=True
initializeEnemy(area)
playerStats()
damageThisBattle=0
elif areaSelect=="DESERT" or areaSelect=="2":
loading_screen(3,"Entering Desert")
area="Desert"
inBattle=True
initializeEnemy(area)
playerStats()
damageThisBattle=0
else:
area="Desert"