3
\$\begingroup\$

The actual code layout of a text adventure. This text adventure is a much-improved sequel to the first code. It is three times as long but three times more efficient. The setting is based on the setting of Telltale's TWD: A New Frontier. The storylines can be found here. I suggest running the code with the storylines before analyzing

import sys
import time


def load(seconds):
    print('\nLoading', end='', flush=True)
    for _ in range(seconds):
        time.sleep(1)
        print('.', end='', flush=True)
    print()


def to_win():
    print('85/15 TO WIN', end='')
    for dot in range(4):
        print('.', end='', flush=True)
        time.sleep(1)
    print('or lose')
    print('Loading', end='', flush=True)
    for _ in range(15):
        time.sleep(1)
        print('.', end='', flush=True)
    print()


class People:
    """Enum to represent the societal positions found in the game"""
    ARMY = "The Army"
    GOVERNMENT = 'The Government'
    CIVILIAN = "Civilians"
    # People is the type of person accessed


class Forces:
    YOU = 'You'
    ENEMY = 'Enemy'


relationships = {People.ARMY: 0, People.CIVILIAN: 0, People.GOVERNMENT: 0}
tide = {Forces.YOU: 50, Forces.ENEMY: 50}

choices = []


def prompt_for_input(prompt, valid_inputs, max_tries=6):
    print(prompt)
    the_roadblock = '\nPlease enter a valid input\n'

    while max_tries > 0:
        user_input = input('> ').upper()

        if user_input in valid_inputs:
            return user_input
        else:
            print(the_roadblock)
            max_tries -= 1

        # the input was not valid, show the roadblock
    print('Seems like you are not willing to play. Goodbye!')
    sys.exit(0)


def change_relation(*args):
    string = ''

    for arg in args:
        type_of_person = arg[0]
        type_of_change = arg[1]
        type_of_change_copy = type_of_change
        """Change the standing of the player with a given faction
        faction and type_of_change are case insensitive and have to correspond to
        class variables of People and RelationshipChanges. type_of_change
        describes by how much the relationship score is altered.
        This function returns a message that describes the change.
        """
        type_translation = {
            "---": -2, "--": -1, "-": -0.5, "+++": 2, "++": 1, "+": 0.5
        }
        if type_of_change in type_translation:
            # only apply the translation if it's own of ---/--/.../+++
            type_of_change_copy = type_translation[type_of_change]

        type_person_name = getattr(People, type_of_person.upper())
        relationships[type_person_name] += type_of_change_copy

        string += '{}{}  '.format(type_of_change, type_of_person).lower()

    return string


def change_tide(change_of_tide):
    tide[Forces.YOU] += change_of_tide
    tide[Forces.ENEMY] -= change_of_tide

    return '\n[{}  %{}|{}%  {}]'.format(Forces.YOU.upper(), tide[Forces.YOU], tide[Forces.ENEMY],
                                        Forces.ENEMY.upper())


def win_loss():
    if tide[Forces.YOU] >= 85:
        return 'VICTORY! The New Frontier has been overpowered and has surrendered. The End.'
    elif tide[Forces.ENEMY] >= 85:
        return 'DEFEAT! The New Frontier has conquered and killed you all. Nice one chief. The End.'
    else:
        return 'PEACE! The war is over and you know live alongside the New Frontier in tranquility.'


def pro_con(skill, pro1, pro2, pro3, con1, con2):
    return '  Skill / Pros / Cons ({} / {}, {}, {} / {}, {})'.format(skill, pro1, pro2, pro3, con1, con2)


def person(name, birthdate, ethnicity, sex, hometown, idea_a, idea_b, pros_cons):
    identity = '  Background & Identity (born: {}, ethnicity: {}, sex: {}, hometown: {})'.format(birthdate, ethnicity,
                                                                                                 sex, hometown)
    aims_belief = '  Aims & Beliefs (A. {}; B. {})'.format(idea_a, idea_b)
    return '{}\n{}\n{}\n{}'.format(name.upper(), identity, aims_belief, pros_cons)


cox_idea1 = '"numbers is key"'
cox_idea2 = '"hit the frontier hard with a direct attack to the most secure but vital part of them: downtown"'
cox_pro_cons = pro_con('militarist', 'quick-minded', 'assertive', 'convincing', 'irrational', 'close-minded')
chloe_cox = person('chloe cox', '09/25/98', 'Caucasian-American', 'F', 'Arlington, VA', cox_idea1, cox_idea2,
                   cox_pro_cons)
vazquez_idea1 = '"strategy is key"'
vazquez_idea2 = '"we weaken every strength, target every weakness and exploit every mistake rationally and ' \
                'intelligently until they fall"'
vazquez_pros_cons = pro_con('strategist', 'smart', 'methodical', 'realistic', 'flawed', 'negligent')
benjamin_vazquez = person('benjamin vazquez', '10/23/88', 'Mexican-American', 'M', 'Richmond, VA', vazquez_idea1,
                          vazquez_idea2, vazquez_pros_cons)
washington_idea1 = '"a prosperous army is key'
washington_idea2 = '"as long as are soldiers are well supplied and well fed, they will fight outstandingly"'
washington_pro_cons = pro_con('supplier', 'considerate', 'benevolent', 'focused', 'old', 'unassertive')
zaid_washington = person('zaid washington', '12/10/74', 'African-American', 'M', 'Virgina Beach, VA',
                         washington_idea1, washington_idea2, washington_pro_cons)
waters_idea1 = '"morale is key"'
waters_idea2 = '"as long as our soldiers have the drive and motivation to fight, they will conquer"'
waters_pro_cons = pro_con('therapist', 'energetic', 'optimistic', 'motivator', 'malleable', 'unassertive')
rob_waters = person('rob waters', '12/17/87', 'Caucasian-American', 'M', 'Roanoke Rapids, NC', waters_idea1,
                    waters_idea2, waters_pro_cons)
li_idea1 = '"firepower and intimidation is key"'
li_idea2 = '''"our priority is our guns, bombs, transportation and technology. we make as much weapons as possible use 
                      them, kill, send a message"'''
li_pro_cons = pro_con('warlord', 'aggressive', 'fearless', 'rational', 'inarticulate', 'young')
ju_li = person('ju_li', '02/06/03', 'Chinese-American', 'F', 'Richmond, VA', li_idea1, li_idea2, li_pro_cons)
lieutenants = [chloe_cox, benjamin_vazquez, rob_waters, zaid_washington, ju_li]


def present_person(people):
    for individual in people:
        print('\n{}'.format(individual))
        load(15)

def start():
    button = prompt_for_input(scavenge, ('X', 'B'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(scavenge_rescue, change_relation(('civilian', '+++'), ('army', '---'),
                                                                       ('government', '---')), change_tide(-5)))
        choices.append('morals: chose lives over land')
        to_win()
        defend()
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(scavenge_remain, change_relation(('civilian', '---'), ('army', '++')),
                                      change_tide(15)))
        choices.append('morals: chose land over lives')
        to_win()
        approach()


def defend():
    button = prompt_for_input(rescue_defend, ('X', 'B', 'Y'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(defend_none, change_relation(('army', '---'), ('civilian', '---'),
                                                                   ('government', '---')), change_tide(-10)))
        choices.append('defence: did nothing')
        to_win()
        losing()
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(defend_some, change_relation(('army', '+++'), ('civilian', '+++'),
                                                                   ('government', '+++')), change_tide(5)))
        choices.append('defence: did something')
        to_win()
        defect()
    elif button == 'Y':
        print('\n{}\n\n{}{}\n'.format(defend_many, change_relation(('army', '-'), ('civilian', '---'),
                                                                   ('government', '---')), change_tide(0)))
        choices.append('defence: did plenty')
        to_win()
        warfare()


def approach():
    button = prompt_for_input(remain_approach, ('X', 'B', 'A'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(approach_north, change_relation(('army', '---'), ('government', '---'),
                                                                      ('civilian', '---')), change_tide(-15)))
        choices.append('approach: used stealth')
        to_win()
        defect()
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(approach_river, change_relation(('army', '+++'), ('government', '+++'),
                                                                      ('civilian', '+++')), change_tide(15)))
        choices.append('approach: targeted stock')
        to_win()
        so_close()
    elif button == 'A':
        print('\n{}\n\n{}{}\n'.format(approach_west_end, change_relation(('army', '--'), ('government', '++'),
                                                                         ('civilian', '+++')), change_tide(10)))
        choices.append('approach: used force')
        to_win()
        so_close()


def so_close():
    button = prompt_for_input(almost, ('X', 'B', 'Y'))
    load(5)

    if button == 'X':
        print('\n\n{}\n\n{}{}\n'.format(almost_supplies, change_relation(('army', '--')), change_tide(-10)))
        choices.append('finishing touch: failed chance at victory')
        to_win()
        spy()
    elif button == 'B':
        print('\n\n{}\n\n{}{}\n'.format(almost_attack, change_relation(('civilian', '---'), ('government', '--')),
                                        change_tide(-10)))
        choices.append('finishing touch: failed chance at victory')
        to_win()
        spy()
    elif button == 'Y':
        print('\n\n{}\n\n{}{}\n\n{}'.format(almost_inside, change_relation(('civilian', '+++'), ('army', '+++'),
                                                                           ('government', '+++')), change_tide(15),
                                            win_loss()))
        choices.append('finishing touch: succeeded and won')


def losing():
    button = prompt_for_input(none_losing, ('X', 'B', 'Y', 'A'))
    load(5)

    if button == 'X':
        print('\n\n{}\n\n{}{}\n'.format(losing_soldiers, change_relation(('army', '++'), ('civilian', '---'),
                                                                         ('government', '--')), change_tide(5)))
        choices.append('priority: valued arms')
        to_win()
        replace()
    elif button == 'B':
        print('\n\n{}\n\n{}{}\n'.format(losing_yields, change_relation(('army', '+'), ('civilian', '+++'),
                                                                       ('government', '+++')), change_tide(20)))
        choices.append('priority: valued production')
        to_win()
        supply_defend()
    elif button == 'Y':
        print('\n{}\n\n{}{}\n'.format(losing_technology, change_relation(('army', '-'), ('civilian', '---'),
                                                                         ('government', '+++')), change_tide(-15)))
        choices.append('priority: valued innovation')
        to_win()
        nuclear()
    elif button == 'A':
        print('\n\n{}\n\n{}{}\n'.format(losing_exploration, change_relation(('army', '--'), ('civilian', '++'),
                                                                            ('government', '+++')), change_tide(30)))
        choices.append('priority: valued outreach')
        to_win()
        persuasion()


def defect():
    button = prompt_for_input(some_north_defect, ('X', 'B', 'Y', 'A'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(defect_execution, change_relation(('civilian', '---'), ('government', '---')),
                                      change_tide(15)))
        choices.append('punishment: execution')
        to_win()
        rebel()
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(defect_prison, change_relation(('civilian', '---'), ('government', '--')),
                                      change_tide(5)))
        choices.append('punishment: incarceration')
        to_win()
        rebel()
    elif button == 'Y':
        print('\n{}\n\n{}{}\n'.format(defect_warn, change_relation(('government', '+++'), ('army', '--')),
                                      change_tide(-10)))
        choices.append('punishment: privileges')
        to_win()
        slaves()
    elif button == 'A':
        print('\n{}\n\n{}{}\n'.format(defect_ignore, change_relation(('government', '---'), ('army', '---')),
                                      change_tide(-15)))
        choices.append('punishment: none')
        to_win()
        slaves()


def warfare():
    button = prompt_for_input(many_warfare, ('X', 'B', 'A'))
    load(5)
    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(warfare_air, change_relation(('army', '+++'), ('government', '+++'),
                                                                   ('civilian', '-')), change_tide(20)))
        choices.append('warfare: aerial')
        to_win()
        peace()
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(warfare_water, change_relation(('government', '--')), change_tide(-5)))
        choices.append('warfare: naval')
        to_win()
        assassination()
    elif button == 'A':
        print('\n{}\n\n{}{}\n'.format(warfare_bio, change_relation(('army', '---'), ('government', '+')),
                                      change_tide(5)))
        choices.append('warfare: biological')
        to_win()
        contaminated()


def nuclear():
    nuke = prompt_for_input(technology_nuke, ('X', 'B'))
    load(5)

    if nuke == 'X':
        change_tide(tide[Forces.ENEMY])
        print('\n{}\n\n{}\n\n{}'.format(nuke_threaten, change_relation(('civilian', '+'), ('army', '+++'),
                                                                       ('government', '+++')), win_loss()))
        choices.append('risk: included nukes')
    elif nuke == 'B':
        print('\n{}\n\n{}{}\n\n{}'.format(nuke_withdraw, change_relation(('civilian', '---'), ('army', '---'),
                                                                         ('government', '---')), change_tide(-15),
                                          win_loss()))
        choices.append('risk: excluded nukes')


def persuasion():
    persuade = prompt_for_input(exploration_persuade, ('X', 'B', 'A'))
    load(5)

    if persuade == 'X':
        print('\n{}\n\n{}{}\n\n{}'.format(persuade_reciprocate, change_relation(('government', '+++'), ('army', '+++')),
                                          change_tide(30), win_loss()))
        choices.append('rebuttal: dodged the predicament')
    elif persuade == 'B':
        print('\n{}\n\n{}{}\n'.format(persuade_lie, change_relation(('government', '---'), ('civilian', '---')),
                                      change_tide(0)))
        choices.append('rebuttal: lied')
        to_win()
        vengeance()
    elif persuade == 'A':
        print('\n{}\n\n{}{}\n'.format(persuade_admit, change_relation(('army', '--')), change_tide(-30)))
        choices.append('rebuttal: admitted')
        change_tide(-30)
        print('{}\n\n{}'.format(persuade_lose, win_loss()))


def supply_defend():
    button = prompt_for_input(yield_supply_defense, ('X', 'B', 'Y'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(supply_defense_defend, change_relation(('government', '-')),
                                      change_tide(-5)))
        choices.append('supply defense: direct')
        to_win()
        blackout()
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(supply_defense_contaminate, change_relation(('government', '+++'),
                                                                                  ('army', '+++')), change_tide(15)))
        choices.append('supply defense: poisonous')
        change_tide(15)
        print('{}\n\n{}'.format(supply_defense_win, win_loss()))
    elif button == 'Y':
        print('\n{}\n\n{}{}\n'.format(supply_defense_conceal, change_relation(('civilian', '++'), ('government', '+')),
                                      change_tide(0)))
        choices.append('supply defense: evasive')
        to_win()
        almost_fifty()


def replace():
    print(soldiers_replace)
    load(15)
    present_person(lieutenants)
    civil = {'first': 0, 'second': 0}
    army = {'first': 0, 'second': 0}
    gov = {'first': 0, 'second': 0}
    valid_stick_input = ['<<', '<', '<>', '>', '>>']

    def balance_relation_change(type_of_person, first_relation_change, second_relation_change):
        get_person = getattr(People, type_of_person.upper())
        relation_change_sum = first_relation_change + second_relation_change
        change_output = ''

        def get_relation_balance(thresholds):
            if relation_change_sum > 0:
                for threshold in thresholds:
                    if relation_change_sum >= threshold:
                        return threshold
            elif relation_change_sum < 0:
                for threshold in thresholds:
                    if relation_change_sum <= threshold:
                        return threshold

        if relation_change_sum < 0:
            for dash in range(abs(relation_change_sum)):
                change_output += '-'
            change_output += str(type_of_person)
            relationships[get_person] += get_relation_balance(range(-4, 0, 1))
        elif relation_change_sum > 0:
            for dash in range(relation_change_sum):
                change_output += '+'
            change_output += str(type_of_person)
            relationships[get_person] += get_relation_balance(range(4, 0, -1))

        return change_output

    left_stick = prompt_for_input(replace_pick_generals, valid_stick_input)

    def pick_left_stick(stick, first_or_second):
        if stick == '<<':
            change_tide(-5)
            army[first_or_second] -= 3
            gov[first_or_second] -= 3
        elif stick == '<':
            change_tide(10)
            army[first_or_second] += 3
            gov[first_or_second] += 3
            civil[first_or_second] += 3
        elif stick == '<>':
            change_tide(-15)
            army[first_or_second] += 2
            gov[first_or_second] -= 3
            civil[first_or_second] -= 3
        elif stick == '>':
            change_tide(5)
            army[first_or_second] += 3
            civil[first_or_second] -= 3
        elif stick == '>>':
            change_tide(15)
            army[first_or_second] += 2
            gov[first_or_second] += 1
            civil[first_or_second] -= 1

        del valid_stick_input[valid_stick_input.index(stick)]

    pick_left_stick(left_stick, 'first')
    load(3)
    left_stick = prompt_for_input('\nYour second?\n', valid_stick_input)
    pick_left_stick(left_stick, 'second')

    def print_results():
        print(change_tide(0))
        for people in [balance_relation_change('army', army['first'], army['second']),
                       balance_relation_change('civilian', civil['first'], civil['second']),
                       balance_relation_change('government', gov['first'], gov['second'])]:
            if people:
                print(people, end='  ')
        print('\n')

    load(5)

    if tide[Forces.YOU] < 40:
        print('\n{}'.format(pick_generals_bad))
        print_results()
        change_tide(-25)
        choices.append('general: chose poorly')
        print('\n{}\n\n{}'.format(replace_lose, win_loss()))
    elif tide[Forces.YOU] > 50:
        print('\n{}'.format(pick_generals_good))
        print_results()
        change_tide(35)
        choices.append('general: chose wisely')
        print('\n{}\n\n{}'.format(replace_win, win_loss()))
    else:
        print('\n{}'.format(pick_generals_ok))
        print_results()
        choices.append('general: chose ineffectively')
        to_win()
        strategy()


def rebel():
    button = prompt_for_input(execution_prison_rebellion, ('X', 'B', 'Y'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(rebellion_quell, change_relation(('army', '+++')), change_tide(5)))
        choices.append('peacekeeping: forceful')
        to_win()
        offer()
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(rebellion_reason, change_relation(('army', '---')), change_tide(-20)))
        choices.append('peacekeeping: peaceful')
        change_tide(-30)
        print('{}\n\n{}'.format(rebellion_lose, win_loss()))
    elif button == 'Y':
        print('\n{}\n\n{}{}\n'.format(rebellion_intimidate, change_relation(('civilian', '---'), ('government', '-'),
                                                                            ('army', '++')), change_tide(15)))
        choices.append('peacekeeping: beneficial')
        change_tide(15)
        print('{}\n\n{}'.format(rebellion_lose, win_loss()))


def slaves():
    button = prompt_for_input(warn_ignore_slaves, ('X', 'B', 'Y', 'A'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(slaves_army, change_relation(('civilian', '---'), ('army', '++')),
                                      change_tide(15)))
        choices.append('punishment: army')
        to_win()
        almost_fifty()
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(slaves_produce, change_relation(('army', '---')), change_tide(-15)))
        choices.append('punishment: production')
        change_tide(-10)
        print('{}\n\n{}'.format(slaves_lose, win_loss()))
    elif button == 'Y':
        print('\n{}\n\n{}{}\n'.format(slaves_plan, change_relation(('government', '++'), ('civilian', '---')),
                                      change_tide(25)))
        choices.append('punishment: plans')
        change_tide(25)
        print('{}\n\n{}'.format(slaves_win, win_loss()))
    elif button == 'A':
        print('\n{}\n\n{}{}\n'.format(slaves_infrastructure, change_relation(('civilian', '---'), ('army', '---')),
                                      change_tide(-5)))
        choices.append('punishment: infrastructure')
        to_win()
        zombies()


def spy():
    button = prompt_for_input(supply_attack_espionage, ('X', 'B', 'A'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(espionage_rush, change_relation(('civilian', '---'), ('army', '---'),
                                                                      ('government', '---')), change_tide(-5)))
        choices.append('patience: impatient')
        to_win()
        offer()
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(espionage_fair, change_relation(('government', '--')), change_tide(-15)))
        choices.append('patience: sufficient')
        to_win()
        blackout()
    elif button == 'A':
        print('\n{}\n\n{}{}\n'.format(espionage_careful, change_relation(('army', '-'), ('government', '+++')),
                                      change_tide(10)))
        choices.append('patience: long')
        change_tide(10)
        print('{}\n\n{}'.format(espionage_win, win_loss()))


def assassination():
    button = prompt_for_input(water_assassinate, ('X', 'B', 'Y'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(assassinate_javier, change_relation(('government', '+++'), ('army', '++')),
                                      change_tide(10)))
        choices.append('safety: 100% (Javier Garcia)')
        to_win()
        almost_fifty()
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(assassinate_gabriel, change_relation(('civilian', '---')), change_tide(-15)))
        choices.append('safety: 50% (Gabriel Garcia)')
        change_tide(-15)
        print('{}\n\n{}'.format(assassinate_lose, win_loss()))
    elif button == 'Y':
        print('\n{}\n\n{}{}\n'.format(assassinate_bullock, change_relation(('civilian', '+++'), ('army', '---'),
                                                                           ('government', '-')), change_tide(25)))
        choices.append('safety: 0% (Jude Bullock)')
        change_tide(20)
        print('{}\n\n{}'.format(assassinate_win, win_loss()))


def peace():
    button = prompt_for_input(air_peace, ('X', 'B', 'A'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(peace_willing, change_relation(('government', '---'), ('army', '---')),
                                      change_tide(10)))
        choices.append('request: trusted')
        change_tide(15)
        print('{}\n\n{}'.format(peace_win, win_loss()))
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(peace_cautious, change_relation(('government', '-')), change_tide(-15)))
        choices.append('request: doubted')
        to_win()
        almost_fifty()
    elif button == 'A':
        print('\n{}\n\n{}{}\n'.format(peace_no, change_relation(('civilian', '---')), change_tide(0)))
        choices.append('request: declined')
        to_win()
        cybersecurity()


def contaminated():
    button = prompt_for_input(bio_contaminated, ('X', 'B'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(contaminated_finish, change_relation(('civilian', '---'), ('government', '---')),
                                      change_tide(-20)))
        choices.append('focus: New Frontier')
        change_tide(-15)
        print('{}\n\n{}'.format(contaminated_lose, win_loss()))
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(contaminated_fix, change_relation(('civilian', '+++'), ('army', '--')),
                                      change_tide(20)))
        choices.append('focus: inhabitants')
        change_tide(20)
        print('{}\n\n{}'.format(contaminated_win, win_loss()))


def strategy():
    button = prompt_for_input(ok_strategy, ('X', 'Y', 'A', 'B'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(strategy_direct, change_relation(('civilian', '---'), ('government', '---')),
                                      change_tide(-20)))
        choices.append('strategy: direct')
        change_tide(-20)
        print(f'{strategy_lose_direct}\n\n{win_loss()}')
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(strategy_wide, change_relation(('civilian', '---'), ('government', '---'),
                                                                     ('army', '---')), change_tide(-20)))
        choices.append('strategy: longitudinal')
        change_tide(-15)
        print(f'{strategy_lose_wide}\n\n{win_loss()}')
    elif button == 'Y':
        print('\n{}\n\n{}{}\n'.format(strategy_psycho, change_relation(('government', '+++'), ('civilian', '-'),
                                                                       ('army', '-')), change_tide(15)))
        choices.append('strategy: psychological')
        change_tide(30)
        print(f'{strategy_win_psycho}\n\n{win_loss()}')
    elif button == 'A':
        print('\n{}\n\n{}{}\n'.format(strategy_patient, change_relation(('army', '+++'), ('civilian', '+++'),
                                                                        ('government', '+++')), change_tide(20)))
        choices.append('strategy: patient')
        change_tide(30)
        print(f'{strategy_win_patient}\n\n{win_loss()}')


def vengeance():
    button = prompt_for_input(lie_revenge, ('X', 'B', 'Y'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(revenge_attack, change_relation(('government', '---'), ('civilian', '-')),
                                      change_tide(-25)))
        choices.append('vengeance: hasty')
        change_tide(-30)
        print('{}\n\n{}'.format(revenge_lose, win_loss()))
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(revenge_wait, change_relation(('government', '+++'), ('civilian', '+++'),
                                                                    ('army', '+++')), change_tide(15)))
        choices.append('vengeance: patient')
        change_tide(20)
        print('{}\n\n{}'.format(revenge_win_wait, win_loss()))
    elif button == 'Y':
        print('{}\n\n{}{}\n'.format(revenge_infiltrate, change_relation(('government', '+++'), ('army', '-'),
                                                                        ('civilian', '+++')), change_tide(15)))
        choices.append('vengeance: strategic')
        change_tide(15)
        print('{}\n\n{}'.format(revenge_win_infiltrate, win_loss()))


def blackout():
    button = prompt_for_input(defend_infrastructure_blackout, ('X', 'B'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(blackout_evacuate, change_relation(('government', '---'), ('army', '---')),
                                      change_tide(-20)))
        choices.append('fight or flight: flight')
        change_tide(-25)
        print(f'{blackout_lose}\n\n{win_loss()}')
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(blackout_stay, change_relation(('civilian', '+++'), ('government', '+++'),
                                                                     ('army', '+++')), change_tide(20)))
        choices.append('fight or flight: fight')
        change_tide(25)
        print(f'{blackout_win}\n\n{win_loss()}')


def offer():
    button = prompt_for_input(quell_rush_offer, ('X', 'B'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}\n\n{}'.format(offer_accept, change_relation(('civilian', '+++'), ('government', '+++')),
                                        win_loss()))
        choices.append('offer: accepted')
    elif button == 'B':
        print('\n{}\n\n{}{}\n\n{}'.format(offer_decline, change_relation(('civilian', '---'), ('government', '---')),
                                          change_tide(25), win_loss()))
        choices.append('offer: declined')


def almost_fifty():
    button = prompt_for_input(army_cautious_conceal_javier_half, ('X', 'B', 'A'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(half_third, change_relation(('civilian', '+++'), ('government', '+++'),
                                                                  ('army', '-')), change_tide(20)))
        choices.append('jeopardy: sent few')
        change_tide(15)
        print(f'{half_win}\n\n{win_loss()}')
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(half_move, change_relation(('civilian', '---'), ('army', '---'),
                                                                 ('government', '---')), change_tide(-25)))
        choices.append('jeopardy: evacuated')
        change_tide(-20)
        print(f'{half_lose}\n\n{win_loss()}')
    elif button == 'A':
        print('\n{}\n\n{}{}\n'.format(half_surround, change_relation(('army', '+++')), change_tide(-10)))
        choices.append('jeopardy: surrounded')
        to_win()
        surrounded()


def zombies():
    button = prompt_for_input(infrastructure_horde, ('X', 'B', 'Y'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(horde_redirect, change_relation(('army', '--')), change_tide(-10)))
        choices.append('horde: redirected')
        change_tide(-10)
        print('{}\n\n{}'.format(horde_lose, win_loss()))
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(horde_lure, change_relation(('civilian', '+++'), ('government', '+++'),
                                                                  ('army', '+')), change_tide(25)))
        choices.append('horde: fed')
        change_tide(30)
        print(f'{horde_win}\n\n{win_loss()}')
    elif button == 'Y':
        print('\n{}\n\n{}{}\n\n{}'.format(horde_clear, change_relation(('civilian', '---')), change_tide(-20),
                                          win_loss()))
        choices.append('horde: cleared')


def cybersecurity():
    button = prompt_for_input(no_hack, ('X', 'B'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(hack_destroy, change_relation(('government', '---')), change_tide(-20)))
        choices.append('cybersecurity: physical')
        change_tide(-30)
        print('{}\n\n{}'.format(hack_lose, win_loss()))
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(hack_cyber, change_relation(('government', '+++'), ('army', '+++')),
                                      change_tide(0)))
        choices.append('cybersecurity: cyber')
        to_win()
        areas()


def areas():
    button = prompt_for_input(cyber_areas, ('X', 'B', 'A'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n\n{}'.format(areas_virginia_beach, change_relation(('civilian', '+++'),
                                                                                ('government', '+++')), change_tide(20),
                                          win_loss()))
        choices.append('city: Virginia Beach')
    elif button == 'B':
        button = prompt_for_input('\n{}'.format(areas_raleigh), ('X', 'B'))
        load(3)
        choices.append('city: Raleigh')

        if button == 'X':
            print('\n{}\n\n{}{}\n\n{}'.format(raleigh_lie, change_relation(('government', '---'), ('civilian', '---')),
                                              change_tide(-65), do_not_lie))
            choices.append('honesty: dishonest')
        elif button == 'B':
            print('\n{}\n\n{}{}\n\n{}'.format(raleigh_honest, change_relation(('government', '+++'), ('army', '++'),
                                                                              ('civilian', '+++')), change_tide(20),
                                              win_loss()))
            choices.append('honesty: honesty')
    elif button == 'A':
        print('\n{}\n\n{}{}\n'.format(areas_dc, change_relation(('civilian', '---')), change_tide(-40)))
        change_tide(-25)
        print('{}\n\n{}'.format(areas_lose, win_loss()))


def surrounded():
    button = prompt_for_input(surround_surrounded, ('X', 'B', 'Y'))
    load(5)

    if button == 'X':
        print('\n{}\n\n{}{}\n'.format(surrounded_richmond, change_relation(('civilian', '---')), change_tide(-20)))
        choices.append('escape: through thinnest')
        change_tide(-25)
        print(f'{surrounded_lose_richmond}\n\n{win_loss()}')
    elif button == 'B':
        print('\n{}\n\n{}{}\n'.format(surrounded_thin, change_relation(('civilian', '+++'), ('government', '+++'),
                                                                       ('army', '+++')), change_tide(20)))
        choices.append('escape: to Richmond')
        change_tide(25)
        print(f'{surrounded_win}\n\n{win_loss()}')
    elif button == 'Y':
        print('\n{}\n\n{}{}\n'.format(surrounded_stay, change_relation(('civilian', '---'), ('government', '---'),
                                                                       ('army', '---')), change_tide(-25)))
        choices.append('escape: no')
        change_tide(-20)
        print(f'{surrounded_lose_stay}\n\n{win_loss()}')


def end():
    infuriate = '\033[38;5;199m' + "INFURIATED" + '\033[m'
    angered = '\033[31m' + "ANGERED" + '\033[m'
    displeased = '\033[38;5;208m' + "DISPLEASED" + '\033[m'
    unimpressed = '\033[93m' + "LEFT UNIMPRESSED," + '\033[m'
    satisfied = '\033[32m' + "SATISFIED" + '\033[m'
    delighted = '\033[36m' + "DELIGHTED" + '\033[m'

    views = [infuriate, angered, displeased, unimpressed, satisfied, delighted]
    thresholds = (-8.5, -6, -4.5, -2, .5)

    def get_final_standing(relation_score):

        for threshold, view in zip(thresholds, views):
            if relation_score <= threshold:
                return view

        return views[-1]

    load(5)
    view_civilians = '\nYou {} the Civilians'.format(get_final_standing(relationships[People.CIVILIAN]))
    view_army = 'You {} the Military'.format(get_final_standing(relationships[People.ARMY]))
    view_government = 'You {} the Government'.format(get_final_standing(relationships[People.GOVERNMENT]))

    for people in [view_civilians, view_government, view_army]:
        print(people)
        time.sleep(4)

    load(5)
    print('\nYOUR DECISIONS:')
    indent = '  '

    for choice in choices:
        print(indent + choice)
        indent += '  '


print(introduction)
load(15)
start()
end()
\$\endgroup\$
  • 2
    \$\begingroup\$ I guess you can post the code without all the dialogs, since there isn't much to review on them. Include one dialog as an example and omit the rest. \$\endgroup\$ – eric.m Aug 27 at 7:31
  • 1
    \$\begingroup\$ IMO your previous title was a lot better than the current one... \$\endgroup\$ – Graipher Aug 27 at 7:54
  • \$\begingroup\$ @eric.m I disagree about omitting the story from the question. If the plot is so complex that it gets in the way of the code, then that's a valid point to be addressed in a review. \$\endgroup\$ – 200_success Aug 27 at 8:56
  • \$\begingroup\$ that's why there's a link to the full version \$\endgroup\$ – Mikey Akamihe Aug 27 at 13:21
4
\$\begingroup\$

Only going to comment on a couple things I noticed while scrolling, not enough time to review the full code.

Be Consistent

Here is your to_win function:

def to_win():
    print('85/15 TO WIN', end='')
    for dot in range(4):
        print('.', end='', flush=True)
        time.sleep(1)
    print('or lose')
    print('Loading', end='', flush=True)
    for _ in range(15):
        time.sleep(1)
        print('.', end='', flush=True)
    print()

Looking through your code, you know when and when not to use an underscore as a loop variable. So, why do you use dot when you don't need to? You should be consistent everywhere in your code.

Docstrings

I may be wrong, but I only noticed one docstring for all your functions and classes. You should include a docstring at the beginning of every module, class, and function you write. It allows documentation to identify what your code is supposed to do. Also helps readers quickly understand your program from reading the module docstring.

Constants Naming

ox_idea1 = '"numbers is key"'
cox_idea2 = '"hit the frontier hard with a direct attack to the most secure but vital part of them: downtown"'
cox_pro_cons = pro_con('militarist', 'quick-minded', 'assertive', 'convincing', 'irrational', 'close-minded')
chloe_cox = person('chloe cox', '09/25/98', 'Caucasian-American', 'F', 'Arlington, VA', cox_idea1, cox_idea2,
                   cox_pro_cons)
vazquez_idea1 = '"strategy is key"'
vazquez_idea2 = '"we weaken every strength, target every weakness and exploit every mistake rationally and ' \
                'intelligently until they fall"'
vazquez_pros_cons = pro_con('strategist', 'smart', 'methodical', 'realistic', 'flawed', 'negligent')
benjamin_vazquez = person('benjamin vazquez', '10/23/88', 'Mexican-American', 'M', 'Richmond, VA', vazquez_idea1,
                          vazquez_idea2, vazquez_pros_cons)
washington_idea1 = '"a prosperous army is key'
washington_idea2 = '"as long as are soldiers are well supplied and well fed, they will fight outstandingly"'
washington_pro_cons = pro_con('supplier', 'considerate', 'benevolent', 'focused', 'old', 'unassertive')
zaid_washington = person('zaid washington', '12/10/74', 'African-American', 'M', 'Virgina Beach, VA',
                         washington_idea1, washington_idea2, washington_pro_cons)
waters_idea1 = '"morale is key"'
waters_idea2 = '"as long as our soldiers have the drive and motivation to fight, they will conquer"'
waters_pro_cons = pro_con('therapist', 'energetic', 'optimistic', 'motivator', 'malleable', 'unassertive')
rob_waters = person('rob waters', '12/17/87', 'Caucasian-American', 'M', 'Roanoke Rapids, NC', waters_idea1,
                    waters_idea2, waters_pro_cons)
li_idea1 = '"firepower and intimidation is key"'
li_idea2 = '''"our priority is our guns, bombs, transportation and technology. we make as much weapons as possible use 
                      them, kill, send a message"'''
li_pro_cons = pro_con('warlord', 'aggressive', 'fearless', 'rational', 'inarticulate', 'young')
ju_li = person('ju_li', '02/06/03', 'Chinese-American', 'F', 'Richmond, VA', li_idea1, li_idea2, li_pro_cons)
lieutenants = [chloe_cox, benjamin_vazquez, rob_waters, zaid_washington, ju_li]

These are all constants. They should be UPPER_CASE to identify them as such.

Meaningful Function Names

def present_person(people):
    for individual in people:
        print('\n{}'.format(individual))
        load(15)

From the name of this function, it seems that the code presents a person. Yet the function accepts people and prints individuals, not one person. Perhaps change the name of this function to make it clear what it's supposed to do.

Unnecessary else after returning

You have this function:

def prompt_for_input(prompt, valid_inputs, max_tries=6):
    print(prompt)
    the_roadblock = '\nPlease enter a valid input\n'

    while max_tries > 0:
        user_input = input('> ').upper()

        if user_input in valid_inputs:
            return user_input
        else:
            print(the_roadblock)
            max_tries -= 1

        # the input was not valid, show the roadblock
    print('Seems like you are not willing to play. Goodbye!')
    sys.exit(0)

After returning in a function, the rest of the code is not executed. So it is unnecessary to have an else here. Your function should look like this now:

def prompt_for_input(prompt, valid_inputs, max_tries=6):
    """
    Docstring here
    """
    print(prompt)
    the_roadblock = '\nPlease enter a valid input\n'

    while max_tries > 0:
        user_input = input('> ').upper()

        if user_input in valid_inputs:
            return user_input
        print(the_roadblock)
        max_tries -= 1

        # the input was not valid, show the roadblock
    print('Seems like you are not willing to play. Goodbye!')
    sys.exit(0)

The same goes for your win_loss function:

def win_loss():
    if tide[Forces.YOU] >= 85:
        return 'VICTORY! The New Frontier has been overpowered and has surrendered. The End.'
    elif tide[Forces.ENEMY] >= 85:
        return 'DEFEAT! The New Frontier has conquered and killed you all. Nice one chief. The End.'
    else:
        return 'PEACE! The war is over and you know live alongside the New Frontier in tranquility.'

You don't need elif and an else here. Just have two if checks for the first two returns, and return the last one if both aren't true. This function should look like this now:

def win_loss():
    """
    Docstring here
    """
    if tide[Forces.YOU] >= 85:
        return 'VICTORY! The New Frontier has been overpowered and has surrendered. The End.'
    if tide[Forces.ENEMY] >= 85:
        return 'DEFEAT! The New Frontier has conquered and killed you all. Nice one chief. The End.'
    return 'PEACE! The war is over and you know live alongside the New Frontier in tranquility.'

Main Guard

You should wrap the code that starts your game in a main guard. It prevents this code from running if you decide to import this program into another program. This StackOverflow answer provides excellent reasoning to what it is and why to use it. So the starting code should look like this:

if __name__ == '__main__':
    print(introduction)
    load(15)
    start()
    end()
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.