""" Text-Based Fighting Game Project started: 4/2/24 Last updated: 5/15/24 Welcome to Text-Based Fighting Game! This is a little personal project I work on when I should be doing incomplete work but choose to do literally anything else instead. Please read the User's Guide before playing! **USER'S GUIDE** --WHAT EACH MOVE DOES-- 1. Punch - a low DMG move that's Garunteed to hit; deals 20 DMG normally, and 40 DMG on crit. 2. Kick - a higher DMG move that has a decent chance to miss; deaLs 35 DMG normally, and 50 on crit. 3. Defend - allows you to brace yourself for the oncoming attack; has a chance to heal HP and remove status effects. 4. Explosion - a magic move that costs 20 MP to cast; deals DMG to all enemies; deals 35 DMG normally, and 50 DMG on crit. --ENEMIES-- Fire Mage - A low HP magic-focused enemy. It can light the player on fire for 3 turns. Necromancer - A stronger enemy; it raises an undead army to do massive DMG all at once! --BOSSES-- Ice Guardian - An ancient guardian constructed with the intention to stop any trespassers. Has a moveset based on ice. --AS A REMINDER-- This game is still under heavy development, and do expect things to break every now and then. I do try to keep the stable build less buggy, but don't be surprised if something isn't working. Thanks for playing, and good luck! (If you're looking for the changelog, it's on the website!) """ print("TEXT-BASED FIGHTING GAME") print("version: 0.4-S") start = input("\nPress enter to start! ") print("\n\n") import random import time #game status vars turn_taken = False #holds if it's the player's turn or not playing = True #holds if the game is continuing or not; used to check if turns should continue global amt_of_turns #holds how many turns have passed amt_of_turns = 0 #debug vars global is_debug_active is_debug_active = False global GM_enabled #toggles god mode GM_enabled = False #health vars global p_hp #holds player HP p_hp = 100 global p_mp p_mp = 20 global turns_stuck turns_stuck = 0 global e_hp #holds enemy HP e_hp = 100 global e_type #holds enemy type global e_num #holds amount of enemies in the current encounter e_num = 1 #BOOKMARK1 global chosen_enem #holds which enemy is selected; is global for printing enemy health remaining global e_dmg_dealt #holds enemy damage amount #status check vars global is_defending #holds if player is defending is_defending = False global will_crit #holds if the next attack will be a critical hit will_crit = False global turns_on_fire #holds how many turns the player is on fire turns_on_fire = 0 global burn_cooldown burn_cooldown = 0 global is_boss #holds if the next encounter will be a boss is_boss = False move_inputted = False #holds if the player input a valid move #enemy status vars global e_slots #holds what enemies are in the slots e_slots = [] global fire_intensity #holds the multiplier for fire damage fire_intensity = 1 global undead_count #holds how many undead the enemy has summoned undead_count = 0 global freeze_cooldown #holds cooldown for b_freeze() freeze_cooldown = 0 global phys_atk_guard phys_atk_guard = False global turns_poisoned turns_poisoned = 0 global poison_strength poison_strength = 1 global explosion_unlocked explosion_unlocked = False global enemies_defeated enemies_defeated = 0 #BOOKMARK2 def lvl_check(): #ran when enemy is defeated global e_num global enemies_defeated global explosion_unlocked if(enemies_defeated == 1): e_num = 2 explosion_unlocked = True print("\nExplosion spell unlocked!\nAt the cost of 20 MP, deal 35 DMG to all enemies!") if(enemies_defeated >= 3): e_num = 3 def punch(): #basic attack: always hits global dmg_dealt global will_crit global phys_atk_guard global turns_poisoned dmg_dealt = 0 if(GM_enabled): print("**GM ENABLED** THE GRAND SLAM SMILES UPON YE") else: print("Punch chosen!") time.sleep(1) if(turns_poisoned > 0): print("The poison reduced the DMG dealt by 5!") dmg_dealt -= 5 if(GM_enabled == True): print("THE ENEMIES COLLAPSE FROM THE HOLY MIGHT OF THE GRAND SLAM") for i in range(e_num): e_hp[i] = 0 print("ALL SHALL KNEEL BEFORE THE GRAND SLAM") dmg_dealt = 0 return if(phys_atk_guard == False): if(will_crit == True): dmg_dealt = 40 print("CRITIAL HIT! Dealt " + str(dmg_dealt) + " damage!") else: dmg_dealt = 20 print("Punch landed! dealt " + str(dmg_dealt) + " damage!") else: print("The enemy was unaffected by the attack!") return(dmg_dealt) def kick(): #higher damage, lower chance of hitting global dmg_dealt global will_crit global turns_poisoned dmg_dealt = 0 print("\nKick chosen!") time.sleep(1) num_rolled = random.randint(1, 6) if(num_rolled <= 4): if(turns_poisoned > 0): print("The poison reduced the DMG dealt by 15!") dmg_dealt -= 15 if(will_crit): dmg_dealt += 50 print("CRITICAL HIT! Dealt " + str(dmg_dealt) + " damage!") else: dmg_dealt += 35 print("Kick landed! dealt " + str(dmg_dealt) + " damage!") else: print("Kick missed! dealt 0 damage!") return(dmg_dealt) def defend(): #heals player and reduces enemy attack dmg by a small amount global p_hp global turns_on_fire global turns_poisoned print("\nDefend chosen!") time.sleep(1) is_defending = True print("You're prepared for the enemy's attack!") time.sleep(1) print("Attempting to heal!") time.sleep(1) num_rolled =random.randint(1,6) if(num_rolled <= 5): #5/6 chance to heal player and recover from statuses print("Healed successfully!") if(turns_on_fire > 1): print("The healing extinguished the flames!") turns_on_fire = 0 fire_intensity = 1 if(turns_poisoned > 0): print("The healing rid your body of the poison!") turns_poisoned = 0 p_hp += 40 print("You are now at " + str(p_hp) + " HP!") else: print("Healing failed!") return(is_defending) def explosion(): global dmg_dealt global p_mp global e_num global e_slots global e_hp global will_crit global phys_atk_guard print("\nExplosion chosen!") time.sleep(1) p_mp -= 20 print("-20 MP! You are now at: " + str(p_mp) + " MP!") time.sleep(1) if(phys_atk_guard == True): print("The explosion broke the guard!") phys_atk_guard = False time.sleep(1) if(will_crit): print("CRITICAL HIT!") dmg_dealt = 50 else: dmg_dealt = 35 for i in range(e_num): e_hp[i] -= dmg_dealt print("Dealt " + str(dmg_dealt) + " DMG to all enemies!") #enemy functions def select_e_type(): #chooses which type of enemy appears global total_e_hp global e_hp global e_num global e_slots global enemies_defeated global is_boss #list of enemies: #Fire Mage (Burn, Melee) #Necromancer (Melee, Raise Dead, Horde Attack) #Cavern Spider (Melee, Poison) (Multi only: web wrap) #(multi only) Medic (Melee, Heal) #potential future enemies: #(multi only) Knight (Crush, Taunt) #potential boss enemies #Guardian of Ice (freeze, crush, ice wall) #Guardian of Fire (burn, smoke wall, flame guard) e_slots = ["empty", "empty", "empty"] e_hp = [0, 0, 0] if(enemies_defeated == 6): is_boss = True if(is_boss == False): for i in range(e_num): e_selected = random.randint(1,12) if(e_selected <= 3): e_type = "Fire Mage" e_slots[i] = "Fire Mage" e_hp[i] = 100 elif(e_selected <= 6): e_type = "Necromancer" e_slots[i] = "Necromancer" e_hp[i] = 120 elif(e_selected <= 9): e_type = "Cave Spider" e_slots[i] = "Cave Spider" e_hp[i] = 80 elif(e_selected <= 12 and e_num > 1): e_type = "Medic" e_slots[i] = "Medic" e_hp[i] = 80 else: e_type = "Cave Spider" e_slots[i] = "Cave Spider" e_hp[i] = 80 else: e_type = "Ice Gaurdian" e_slots[0] = "Ice Guardian" e_slots[1] = "empty" e_slots[2] = "empty" e_num = 1 e_hp[0] = 200 return(e_slots) #enemy attacks def e_melee(): global is_defending global e_dmg_dealt global p_hp print("\nThe enemy goes for a melee attack!") if(is_defending): e_dmg_dealt = 8 print("Defended the hit! Reduced DMG taken!") print("The melee hit! Dealt 8 DMG to player!") p_hp -= e_dmg_dealt is_defending = False time.sleep(2) else: e_dmg_dealt = 14 print("The melee hit! Dealt 14 DMG to player!") p_hp -= e_dmg_dealt time.sleep(2) def e_burn(): #applies DoT that can be removed by healing global turns_on_fire global burn_cooldown global fire_intensity global e_dmg_dealt print("\nThe enemy is preparing a spell!") if(turns_on_fire > 0): time.sleep(1) num_rolled = random.randint(1,10) if(e_num > 1): #if just more than 1 enemy, have chance to fail num_rolled = random.randint(1,10) if(num_rolled <= 7): #if check passes, light player ablaze print("The enemy casted fireball!") if(fire_intensity > 0): #if player wasnt alr on fire print("The fire grows in intensity!\nYou now take double fire damage!") turns_on_fire = 2 fire_intensity = 2 e_dmg_dealt = 4 burn_cooldown = 2 else: print("You are now on fire for the next 2 turns!") turns_on_fire = 2 e_dmg_dealt = 4 burn_cooldown = 2 time.sleep(2) else: print("But it failed!") e_dmg_dealt = 0 else: print("The enemy casted fireball!") print("You are now on fire for the next 2 turns!") turns_on_fire = 2 #lights player on fire for 2 turns e_dmg_dealt = 4 time.sleep(2) burn_cooldown = 4 return(e_dmg_dealt) def raise_dead(): #NECROMANCER: adds +1 undead; boosts horde attack dmg and base atk #NOTE: add chance for spell to fail ONLY IN MULTI-ENEMY ENCOUNTERS global undead_count print("\nThe enemy is preparing a spell!") time.sleep(1) print("The enemy raised the undead!") undead_count += 1 print("Current enemy undead raised: " + str(undead_count)) return(undead_count) def horde_atk(): #NECROMANCER: Uses all undead in a large attack; dmg scales with undead_count global undead_count global e_dmg_dealt global is_defending print("\nThe enemy is preparing their horde for an attack!") time.sleep(1) time.sleep(1) if(is_defending): print("The horde charges you, but you were defending!") e_dmg_dealt = 6 + undead_count else: print("The horde charges you!") e_dmg_dealt = 10 + (undead_count * 4) time.sleep(1) print("The horde dealt " + str(e_dmg_dealt) + " damage with " + str(undead_count) + " undead!") time.sleep(1) print("All the undead withered away...") undead_count = 0 time.sleep(2) return(e_dmg_dealt) def e_poison(): global e_dmg_dealt global turns_poisoned global poison_strength print("The enemy is preparing an attack!") time.sleep(1) print("The enemy bit you with poisonous fangs! Dealt 6 DMG!") e_dmg_dealt = 6 turns_poisoned += 2 print("You are now poisoned for " + str(turns_poisoned) + " turns!") return(e_dmg_dealt) def e_web_wrap(): global turns_stuck global e_dmg_dealt print("The enemy is preparing an attack!") time.sleep(1) print("The enemy trapped you in a web! You are unable to move!") turns_stuck += 1 def e_heal(): global e_hp global e_slots print("The enemy is preparing a spell!") time.sleep(1) for i in range(len(e_hp)): if(e_slots[i] != "Medic"): e_hp[i] += 30 print("Healed all other enemies by 30 HP!") #boss attacks def b_freeze(): global turns_stuck global freeze_cooldown print("The Ice Guardian is preparing a spell!") time.sleep(1) #freeze player for 1 turn; have 3 turn cooldown turns_stuck = 1 freeze_cooldown = 3 print("The Ice Guardian froze you!") time.sleep(1) return(turns_stuck) def b_crush(): global dmg_dealt print("The Ice Guardian raises their weapon!") if(is_defending): dmg_dealt = 15 print("Defended the hit! Reduced DMG taken!") else: dmg_dealt = 30 print("The Ice Guardian crushes you, dealing " + str(dmg_dealt) + " DMG!") return(dmg_dealt) def b_ice_wall(): global phys_atk_guard print("The Ice Guardian is preparing a spell!") time.sleep(1) phys_atk_guard = True print("The Ice Guardian raises a thick wall of ice, guarding against physical attacks!") time.sleep(1) def death_message(): print("\n\n\n\nYOU DIED\n\n\n\n") playing = False #beginning of game very_normal_variable = "GRANDSLAM" if(start == very_normal_variable): print("DEBUG MODE ENABLED!") enable_GM = input("Enable God Mode? (y/n) ") if(enable_GM == "y"): GM_enabled = True if(GM_enabled == True): print("**GM ENABLED**") p_hp = 999999 #*technically* you could still die. good luck doing that though. e_slots = select_e_type() for i in range(len(e_slots)): if(e_slots[i] != "empty"): print(str(e_slots[i]) + " approaches!"); while(playing == True): if(p_hp <= 0): death_message() break while(turn_taken == False): #finish/continue code if(e_hp[0] <= 0 and e_hp[1] <= 0 and e_hp[2] <= 0): time.sleep(2) if(is_boss): print("\n\nBoss slain! Congratulations!") is_boss = False else: print("\n\nAll enemies slain!") enemies_defeated += e_num print("Total enemies slain: " + str(enemies_defeated)) lvl_check() if(p_hp <= 50): print("You found a health potion on the ground.\n Healed 60 HP and removed all status effects!") p_hp += 60 turns_poisoned = 0 turns_on_fire = 0 turns_stuck = 0 print("you are now at " + str(p_hp) + " HP!") print("\n\nFinding new enemies…\n") time.sleep(2) e_slots = select_e_type() for i in range(len(e_slots)): if(e_slots[i] != "empty"): print(str(e_slots[i]) + " approaches!"); time.sleep(0.5) time.sleep(0.5) amt_of_turns = 0 move_inputted = False #player chooses move via 4 options time.sleep(1) amt_of_turns += 1 print("\n\n~~TURN " + str(amt_of_turns) + "~~\n\n") print("--PLAYER TURN--") if(p_mp < 20): p_mp += 10 print("\nRecovered 10 MP!") print("[" +str(p_mp) + " MP remaining]\n") if(turns_poisoned > 0): print("The poison weakened you…\nNext attack will do reduced DMG!") print("Poisoned for: " + str(turns_poisoned) + " turns!") if(turns_stuck == 0): while(move_inputted == False): print("Choose a move:") if(GM_enabled): print("1. CALL UPON THE MIGHT OF THE DENNY'S GRAND SLAM") elif(phys_atk_guard == True): print("1. punch (Will have no effect!)") print("2. kick (will have no effect!)") else: print("1. punch") print("2. kick") print("3. defend") if(explosion_unlocked and p_mp >= 20): print("4. explosion (-20 MP)") elif(explosion_unlocked and p_mp < 20): print("4. explosion (NOT ENOUGH MP)") try: chosen_move = int(input("Enter a number here: ")) except ValueError: print("\nInvalid input! Try again.\n") chosen_move = 0 continue if(chosen_move > 4 or chosen_move < 1): print("\nNot within valid range! Try again.\n") time.sleep(1) chosen_move = 0 continue elif(chosen_move == 4 and p_mp < 20): print("Not enough MP! Try again.\n") time.sleep(1) continue else: move_inputted = True num_rolled = random.randint(1,10) if(num_rolled >= 8): will_crit = True if(chosen_move < 3 and GM_enabled == False): #player chooses enemy using e_slots if(e_num > 1): print("\nChoose an enemy:") for i in range(len(e_slots)): #for each slot if(e_slots[i] != "empty"): #if the slot isn't empty if(e_hp[i] < 1): print(str(i+1) + ": " + str(e_slots[i]) + ", DEAD") else: print(str(i+1) + ": " + str(e_slots[i]) + ", " + str(e_hp[i]) + " HP") #print slot num + enemy in slot try: chosen_enem = int(input("Enter a number here: ")) except ValueError: print("\nInvalid input! Try again.") chosen_enem = 0 continue if(chosen_enem > e_num or chosen_enem <= 0): print("\nOutside of range! Try again.") amt_of_turns -= 1 continue if(e_hp[chosen_enem-1] <= 0): print("That enemy is already dead! Try again.") continue enem_selected = e_slots[chosen_enem-1] print("\nEnemy selected: " + enem_selected) print("\n--------------------------------------\n") else: chosen_enem = 1 #if there's only 1 enemy, skip over selection if(turns_on_fire >= 1): p_hp -= (6 * fire_intensity) print("\nYou're on fire! The burns dealt " + str(6 * fire_intensity) + " damage!") turns_on_fire -= 1 if(p_hp <= 0): death_message() print("You are now at: " + str(p_hp) + " HP!") time.sleep(1) if(chosen_move == 1): dmg_dealt = punch() if(GM_enabled == False): e_hp[chosen_enem-1] -= dmg_dealt #included here since it isn't returned by defend elif(chosen_move == 2): dmg_dealt = kick() e_hp[chosen_enem-1] -= int(dmg_dealt) #see comment above elif(chosen_move == 3): is_defending = defend() elif(chosen_move == 4): if(explosion_unlocked): explosion() else: print("Outside of range! Try again.") continue else: print("\nYou try to move, but you're stuck in place!\n") time.sleep(2) turns_stuck = 0 if(e_hp[0] > 0 or e_hp[1] > 0 or e_hp[2] > 0): #if any enemy has hp above 0 turn_taken = True #as long as the enemy isn't dead, make sure to give it a turn #enemy turn while(turn_taken == True): will_crit = False time.sleep(2) print("\n--------------------------------------\n") print("\n--ENEMY TURN--") if(is_boss == False): #if enemy isn't a boss for i in range(e_num): #for each enemy if(e_hp[i] > 1): #if enemy is alive if(e_slots[i] == "Fire Mage"): #if that enemy is a fire mage num_rolled = random.randint(1,6) if(num_rolled <= 2): e_melee() elif(burn_cooldown <= 0): e_burn() else: e_melee() burn_cooldown -= 1 elif(e_slots[i] == "Necromancer"): num_rolled = random.randint(1,9) if(num_rolled <= 5): raise_dead() elif(num_rolled <= 9 and undead_count >= 1): p_hp -= horde_atk() else: raise_dead() elif(e_slots[i] == "Cave Spider"): num_rolled = random.randint(1,9) if(num_rolled <= 3): e_poison() elif(num_rolled <= 6 and e_num > 1): #multi exclusive bc it'd b annoying in single-enemy encounters e_web_wrap else: e_melee() elif(e_slots[i] == "Medic"): num_rolled = random.randint(1,6) if(num_rolled <= 2): e_heal() else: e_melee() else: if(e_slots[0] == "Ice Guardian"): num_rolled = random.randint(1,9) if(num_rolled <= 3 and freeze_cooldown == 0): b_freeze() #(makes player immobile for a turn) elif(num_rolled <= 6): p_hp -= b_crush() #(does a large amt of DMG to player) elif(num_rolled <= 9): b_ice_wall() #(gives the enemy a shield that absorbs phys dmg) print("\n--------------------------------------\n") print("\nPlayer HP remaining: " + str(p_hp)) for i in range(e_num): #print remaining hp of all enemies if(e_hp[i] <= 0): print("Enemy " + str(i+1) + " HP remaining: DEAD") else: print("Enemy " + str(i+1) + " HP remaining: " + str(e_hp[i])) print("\n--------------------------------------") time.sleep(1) turn_taken = False move_inputted = False is_defending = False