def territoryConquered(self, base, target, defender): self.addCard = True self.choice = False GUI.updateBoard(target) GUI.highlight(base, False) self.eliminated(defender) if Data.checkWin(): #break out of attack - handle win logging.info(Data.playerList[self.player].name+' wins') UI.box1 = Data.playerList[self.player].name+' Wins!' UI.box2 = 'World Domination Complete' UI.box3 = 'Interested in a rematch?' UI.update() self.pick = False else: logging.info('Territory conquered') UI.box3 = 'Territory conquered' UI.update() if Data.terrList[base].units > 1: troops = Data.terrList[base].units - 1 Data.terrList[base].units -= troops GUI.displayUnits() GUI.drawLines(base, target) self.placement(troops, base, target) bonus = self.cardChoice(False) if bonus > 0: self.placement(bonus)
def eliminated(self, defender): if Data.playerList[defender].units == 0 and Data.playerList[defender].terr == 0: c = Data.playerList[defender].cards Data.playerList[defender].cards = 0 Data.playerList[self.player].cards += c UI.eliminatedLine(defender) UI.update() return True return False
def placing(num): Data.terrList[terr].units += num if base == None: Data.playerList[self.player].units += num if num > 1: UI.box3 = str(num)+' troops added' else: UI.box3 = str(num)+' troop added' UI.update() GUI.highlight(terr, True)
def startingPlace(self): self.troops = Data.addNum() UI.box1 = Data.playerList[self.player].name+' - '+str(self.troops)+' to Place' bonus = self.cardChoice(True) if bonus != None: self.troops += bonus UI.nextMsg = 'Attack' UI.box1 = Data.playerList[self.player].name+' - Place Units' UI.box3 = 'Click territories to place units' UI.update() logging.info(str(self.troops)+' troops to add') self.placement(self.troops)
def attack(self): UI.nextMsg = 'Fortify' UI.nextHover = False UI.update() #loop to get appropriate attacking territory or advance to fortify while self.pick and not self.restart: UI.nextColor = True UI.box1 = Data.playerList[self.player].name+' - Attack' UI.box2 = 'Select one of your territories' UI.box3 = 'to launch attack from' UI.update() base = self.clickMapAny(True) if base == None or not base: self.pick = False else: self.choice = True #set default troops to max attackers, can be changed by player self.numAttackers = min(Data.terrList[base].units-1, 3) UI.numBoxSetArray(base, self.numAttackers) #loop to get target or handle break to send back to first loop while self.choice and not self.restart: UI.nextColor = False UI.update() GUI.drawLines(base, None) target = self.clickMapSpecific(base) if target != None and target != False: #roll dice, handle results defender = Data.terrList[target].owner attLoss, defLoss, change = self.dice(base, target) logging.info('Attacker lost '+str(attLoss)+', defender lost '+str(defLoss)+', change: '+str(change)) UI.box2 = ('You lost '+str(attLoss)+', defender lost '+str(defLoss)) UI.box3 = ('Click to attack again or water to reset') UI.update() #handle for less available attackers if Data.terrList[base].units-1 < self.numAttackers: self.numAttackers = Data.terrList[base].units-1 GUI.displayUnits() #not enough units to keep attacking if change == False: logging.info('Too few units to continue attacking') GUI.highlight(base, False) GUI.highlight(target, False) self.choice = False #territory conquered if change: self.territoryConquered(base, target, defender)
def fortify(self): UI.nextMsg = 'End Turn' UI.nextHover = False UI.box1 = Data.playerList[self.player].name+' - Fortify' UI.update() while self.done and not self.restart: UI.nextColor = True UI.box2 = ('Select territory to move units') UI.box3 = ('Click \'End Turn\' when finished') UI.update() base = self.clickMapAny(False) if base == None or not base: break else: troops = Data.terrList[base].units - 1 Data.terrList[base].units -= troops GUI.highlight(base, False) self.placement(troops, base, False) GUI.setMap()
def placement(self, troops, base=None, style=None): troops = troops def placing(num): Data.terrList[terr].units += num if base == None: Data.playerList[self.player].units += num if num > 1: UI.box3 = str(num)+' troops added' else: UI.box3 = str(num)+' troop added' UI.update() GUI.highlight(terr, True) UI.nextColor = False #loop while there are troops to place while troops > 0 and not self.restart: UI.box2 = str(troops)+' unit(s) to place' UI.update() if style == None: terr, click = self.clickMapAny() else: GUI.drawLines(base, style) terr, click = self.clickMapSpecific(base, style) if click != None: #left click places one unit if click == 1: placing(1) troops -= 1 #right click places multiple units - 10, 5, or remaining elif click == 3: #if more than 50 troops to place, place 10 at a time if troops >= 50: placing(10) troops -= 10 #if less than 50 but more than 5, place 5 at a time elif 50 > troops > 5: placing(5) troops -= 5 #if less than 5 troops, place remaining else: placing(troops) troops -= troops time.sleep(.05) GUI.highlight(terr, False)
def rematch(self): UI.nextMsg = 'Rematch' UI.nextColor = True UI.nextHover = True UI.update() while True and not self.restart: (x,y), click = getMouseClick(True) if 305 < x < 333 and 518 < y < 546: Intro.menu() if Data.reset == True: self.breakMove() elif 618 < x < 717 and 518 < y < 546: if click == 1: #handle for rematch logging.info('Rematch selected') Data.reset = True self.breakMove() else: continue
def cardChoice(self, style): bonus = 0 cashing = style additional = False #handle for eliminated player if not style: cards = Data.playerList[self.player].cards if cards >= 6: while cards > 4: bonus += Data.getCardCash() Data.cardCount += 1 cards -= 3 if bonus > 0: UI.box3 = ('Cards cashed - '+str(bonus)+' extra units') UI.update() return bonus #handle for beginning of turn while cashing and not self.restart: cards = Data.playerList[self.player].cards if cards < 3: #not enough to cash cashing = False if bonus == 0: UI.box3 = 'Select territories to place units' return bonus elif cards >= 5: #forced to cash bonus += Data.getCardCash() Data.cardCount += 1 logging.info('Cards cashed - '+str(bonus)+' extra units') UI.box3 = ('Cards cashed - '+str(bonus)+' extra units added') UI.update() additional = True elif 3 <= cards < 5: #handle if given a choice to cash if additional: UI.box1 = Data.playerList[self.player].name+' - '+str(self.troops+bonus)+' to Place' UI.box2 = 'Would you like to cash extra cards?' else: UI.box2 = 'Would you like to cash your cards?' UI.box3 = 'Click \'Cash\' if so or click the map' UI.nextMsg = 'Cash' UI.nextColor = True UI.nextHover = False UI.update() #get click - map if not cashing, button if cashing while True and not self.restart: (x,y), click = getMouseClick(True) if y < 512: logging.info('Player not cashing') cashing = False return bonus elif 305 < x < 333 and 518 < y < 546: Intro.menu() if Data.reset == True: logging.info('Restart selected') self.breakMove() return None elif 618 < x < 717 and 518 < y < 546: if click == 1: bonus += Data.getCardCash() Data.cardCount += 1 logging.info('Cards cashed - '+str(bonus)+' extra units') UI.box3 = ('Cards cashed - '+str(bonus)+' extra units added') choice = False return bonus else: continue
def tutorial(self, style=False): UI.makeButton(black,0,0,GUI.width,GUI.height,'',0) UI.makeButton(grey,2,2,GUI.width-4,GUI.height-4,'',0) msgA = "This is a Risk simulation I built in python to practice programming. I hope you enjoy it!" msgB = "Please take note - there are a few changes from the original rules:" msgC = "Initial territory and troop placement is randomized." msgD = "Cards have been simplified. You may cash your cards when you have 3 or 4." msgE = "Cards are automatically cashed when you have 5 or more." msgF = "Attacking territories will default to use the maximum number of dice, but can be changed." msgG = "Defending territories will automatically use the maximum number of dice." msgH = "Pro Tip: when placing units, you can left click to add 1 or right click to add 5." msgI = "If there are less than 5 to add, all of the remaining units will be added." msgJ = "You can check out the source code on my github: https://github.com/adsnash" msgK = "If you are unfamiliar with the rules of Risk, please visit: http://www.hasbro.com/common/instruct/risk.pdf" msgL = "Legal disclaimer: Risk is a registered trademark of Parker Brothers. This simulation is for educational purposes only." msgM = "I do not claim to own any of Parker Brothers’ intellectual property. Please don’t sue me!" msgAr = [msgB,msgC,msgD,msgE,msgF,msgG,msgH,msgI] UI.makeButton(grey,250,20,500,50,'Welcome to my Risk Simulation!',45) UI.makeButton(grey,150,80,700,25,msgA,16) down = 30 for i in range(len(msgAr)): UI.makeButton(grey,150,(120+(down)*i),700,30,msgAr[i],20) UI.makeButton(grey,50,460,900,20,msgJ,16) UI.makeButton(grey,50,490,900,20,msgK,16) UI.makeButton(grey,50,530,900,20,msgL,13) UI.makeButton(grey,50,555,900,20,msgM,13) UI.makeButton(black,385,380,180,60,'',0) UI.makeButton(red,390,385,170,50,'Got it!',30) intro = True while intro: mouse = pygame.mouse.get_pos() click = pygame.mouse.get_pressed() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if 390 < mouse[0] < 390+170 and 385 < mouse[1] < 435: UI.makeButton(brightRed,390,385,170,50,'Got it!',30) if click[0] == 1: intro = False else: UI.makeButton(red,390,385,170,50,'Got it!',30) if style: self.menu()
def clickMapSpecific(self, base, style=None): while True and not self.restart: GUI.drawLines(base, style) #add numberBox here - or in clickMapSpecific if style == None: UI.numBoxSetArray(base, self.numAttackers) UI.numBox() #could be handled with a none (x,y), click = getMouseClick(style) else: (x,y), click = getMouseClick() if y > 512: #handle for menu - button will not be live if 305 < x < 333 and 518 < y < 546: Intro.menu() if Data.reset == True: logging.info('Restart selected') self.breakMove() if style == None: return None else: return None, None else: continue else: waterBreak = True #set self.numAttackers without resetting from water click margin = 80 for i in range(3): if style == None and (405+margin*i) < x < (405+margin*i+30) and (470) < y < (470+30): self.numAttackers = i+1 waterBreak = False p = GUI.MasterMap.get_at((x,y)) #handle for water click reset if p[0] == 162 and style == None and waterBreak: self.choice = False logging.info('Water clicked - resetting') UI.box2 = ('Resetting selected territory') UI.box3 = ('Select territory to attack from') UI.update() GUI.highlight(base, False) return False elif 0 < p[0] < 43: #redistribute - only base or conquered territory if type(style) is int and 0 < style < 43: if p[0] == style or p[0] == base: return p[0], click else: logging.info('Must be attacking or new territory') UI.box3 = 'Must be attacking or new territory' UI.update() continue else: if p[0] not in Data.terrList[base].touch or p[0] != base: logging.info('Territories must be touching') UI.box2 = 'Territories must be touching' if p[0] in Data.terrList[base].touch or p[0] == base: #fortify - base or connected owned territories if style == False: if Data.terrList[p[0]].owner == self.player: return p[0], click else: logging.info('Must choose your own territory') UI.box3 = 'Must choose your own territory' UI.update() continue #attack - connected non-owned territories elif style == None: if Data.terrList[p[0]].owner != self.player: return p[0] #handle for clicking same country - reset elif p[0] == base: self.choice = False logging.info('Resetting selected territory') UI.box2 = ('Resetting selected territory') UI.box3 = ('Select territory to attack from') UI.update() GUI.highlight(p[0], False) return False else: logging.info('Cannot attack owned territory') UI.box2 = 'Cannot attack owned territory' UI.update() continue
def getMouseClick(hover=False): pygame.event.pump() pygame.event.clear() while True: (x,y) = pygame.mouse.get_pos() #highlight playerToken when mouse hovers over it if 304 < x < 333 and 518 < y < 547: if UI.tokenHover == False: UI.tokenHover = True UI.playerToken() #highlight nextButton when mouse hovers over it elif hover and 617 < x < 717 and 518 < y < 547: if UI.nextHover == False: UI.nextHover = True UI.nextButton() #highlight numberBoxes when mouse hovers over it elif hover == None: click = pygame.mouse.get_pressed() margin = 80 for i in range(3): if (405+margin*i) < x < (405+margin*i+30) and (470) < y < (470+30): if UI.numBoxAr[i] == Data.playerList[Data.turn].color: color = Data.playerList[Data.turn].bright UI.makeButton(color,(405+margin*i),470,30,30,str(i+1),20) else: color = UI.numBoxAr[i] UI.makeButton(color,(405+margin*i),470,30,30,str(i+1),20) else: if UI.tokenHover == True: UI.tokenHover = False UI.playerToken() elif UI.nextHover == True: UI.nextHover = False UI.nextButton() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() #handle for left and right click. 1 for left click, 3 for right if event.type == pygame.MOUSEBUTTONDOWN: if event.button == 1: return (event.pos, event.button) elif event.button == 3: return (event.pos, event.button)
def confirm(self): msg = "Are you sure? This action cannot be undone." UI.makeButton(water,450,440,100,20,msg,17) UI.makeButton(black,365,470,110,35,'',0) UI.makeButton(green,370,475,100,25,'Yes',20) UI.makeButton(black,525,470,110,35,'',0) UI.makeButton(red,530,475,100,25,'No',20) confirm = True choice = False while confirm: pygame.event.pump() pygame.event.clear() mouse = pygame.mouse.get_pos() click = pygame.mouse.get_pressed() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() #highlight yes button and handle click if (365) < mouse[0] < (365+110) and (470) < mouse[1] < (470+35): UI.makeButton(brightGreen,370,475,100,25,'Yes',20) if click[0] == 1: logging.info('Player clicked to restart') choice = True confirm = False #highlight no button and handle click elif (530) < mouse[0] < (530+110) and (470) < mouse[1] < (470+35): UI.makeButton(brightRed,530,475,100,25,'No',20) if click[0] == 1: confirm = False else: UI.makeButton(green,370,475,100,25,'Yes',20) UI.makeButton(red,530,475,100,25,'No',20) if choice: Data.reset = True return False else: self.menu()
def pickPlayer(self): UI.makeButton(black,0,0,GUI.width,GUI.height,'',0) UI.makeButton(grey,2,2,GUI.width-4,GUI.height-4,'',0) UI.makeButton(grey,250,100,500,100,'Get ready to start!',50) UI.makeButton(grey,250,200,500,100,'How many players?',40) margin = 130 col = [red,blue,green,yellow,purple] bri = [brightRed,brightBlue,brightGreen,brightYellow,brightPurple] for i in range(5): c = col[i] UI.makeButton(black,(195+margin*i),345,90,90,'',0) UI.makeButton(c,(200+margin*i),350,80,80,str(i+2),38) picking = True numberPlayers = 0 while picking: mouse = pygame.mouse.get_pos() click = pygame.mouse.get_pressed() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() #highlight number buttons for j in range(5): if (195+margin*j) < mouse[0] < (195+margin*j+90) and (345) < mouse[1] < (345+90): c = bri[j] UI.makeButton(c,(200+margin*j),350,80,80,str(j+2),38) if click[0] == 1: #get number of players numberPlayers = j+2 picking = False else: c = col[j] UI.makeButton(c,(200+margin*j),350,80,80,str(j+2),38) logging.info(str(numberPlayers)+' players selected') return numberPlayers
def introMap(self): intro = True GUI.setMenu() msgA = "This map shows the different continents and the connections between territories." msgB = "Click the current player at token any time to see this map again." msgC = "Please note: the button to move to the next phase of your turn will be red when active or grey if action must be taken." msgAr = [msgA,msgB,msgC] UI.makeButton(black,0,512,GUI.width,100,'',0) UI.makeButton(grey,2,513,GUI.width-4,97,'',0) down = 30 for i in range (3): UI.makeButton(grey,50,(520+down*i),900,20,msgAr[i],16) UI.makeButton(black,385,445,180,60,'',0) UI.makeButton(red,390,450,170,50,'Let\'s Play!',30) while intro: mouse = pygame.mouse.get_pos() click = pygame.mouse.get_pressed() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if 390 < mouse[0] < 390+170 and 450 < mouse[1] < 500: UI.makeButton(brightRed,390,450,170,50,'Let\'s Play!',30) if click[0] == 1: intro = False else: UI.makeButton(red,390,450,170,50,'Let\'s Play!',30)
def menu(self): UI.info() GUI.setMenu() UI.makeButton(white,280,516,440,90,'',0) UI.makeButton(black,480,529,40,40,'',0) UI.makeButton(Data.playerList[Data.turn].color,485,534,30,30,'',0) UI.makeButton(white,440,578,120,20,Data.playerList[Data.turn].name,20) col = [red,yellow,green,blue] bri = [brightRed,brightYellow,brightGreen,brightBlue] msg = ['Resume','Restart','Tutorial','Hints'] xInc = 255 yInc = 49 menu = True style = None for i in range(4): side = i%2 down = i//2 UI.makeButton(black,(305+side*xInc),(519+down*yInc),135,35,'',0) UI.makeButton(col[i],(310+side*xInc),(524+down*yInc),125,25,msg[i],25) while menu: pygame.event.pump() pygame.event.clear() mouse = pygame.mouse.get_pos() click = pygame.mouse.get_pressed() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() #highlight/get click if mouse enters player token if (480) < mouse[0] < (480+40) and (529) < mouse[1] < (529+40): UI.makeButton(Data.playerList[Data.turn].bright,485,534,30,30,'',0) if click[0] == 1: style = 0 menu = False else: UI.makeButton(Data.playerList[Data.turn].color,485,534,30,30,'',0) for j in range(4): side = j%2 down = j//2 #highlight/get click if mouse enters button if (305+side*xInc) < mouse[0] < (305+side*xInc+135) and (519+down*yInc) < mouse[1] < (519+down*yInc+35): UI.makeButton(bri[j],(310+side*xInc),(524+down*yInc),125,25,msg[j],25) if click[0] == 1: style = j menu = False else: UI.makeButton(col[j],(310+side*xInc),(524+down*yInc),125,25,msg[j],25) #handle each button with appropriate method if style == 0: GUI.setMap() if style == 1: self.confirm() if style == 2: self.tutorial(True) if style == 3: self.hints()
def clickMapAny(self, style=None): button = False if style != None: button = True while True and not self.restart: (x,y), click = getMouseClick(button) if y > 512: #handle for button and menu if 305 < x < 333 and 518 < y < 546: Intro.menu() if Data.reset == True: logging.info('Restart selected') self.breakMove() if style == None: return None, None else: return None if button and 618 < x < 717 and 518 < y < 546: return False else: continue else: p = GUI.MasterMap.get_at((x,y)) #output not owned territory if 0 < p[0] < 43 and Data.terrList[p[0]].owner != self.player: logging.info('Not your territory') UI.box3 = 'Must select your own territory' UI.update() time.sleep(.05) continue elif 0 < p[0] < 43 and Data.terrList[p[0]].owner == self.player: #None for placing units if style == None: return p[0], click #handle for right click elif click == 3: continue #handle for too few units elif click == 1 and Data.terrList[p[0]].units < 2: GUI.highlight(p[0], True) logging.info('Must have more than 1 unit') UI.box3 = 'Must have more than 1 unit' UI.update() time.sleep(.05) GUI.highlight(p[0], False) continue #attack/fortify elif click == 1 and Data.terrList[p[0]].units > 1: #make sure there are targets to pick from targets = False for i in Data.terrList[p[0]].touch: #True for attack, False for fortify if style and Data.terrList[i].owner != self.player: UI.box2 = ('Select enemy territory to attack') UI.box3 = ('Click water/same territory to reset') UI.update() targets = True break elif not style and Data.terrList[i].owner == self.player: targets = True UI.box3 = 'Territories must be touching' break #needs output to user if targets: GUI.highlight(p[0], True) return p[0] #handle for no enemies to attack else: GUI.highlight(p[0], True) logging.info('No valid connecting territories') UI.box3 = 'No valid connecting territories' UI.update() time.sleep(.05) GUI.highlight(p[0], False) continue
def hints(self): UI.makeButton(black,0,0,GUI.width,GUI.height,'',0) UI.makeButton(grey,2,2,GUI.width-4,GUI.height-4,'',0) msgA = "Try to take the smaller continents like South America or Australia, especially early on." msgB = "If an opponent holds a continent, take one of its territories to prevent him getting the bonus." msgC = "Card cash is the key to victory – every subsequent amount will be larger than the last." msgD = "Eliminating opponents gives you their cards – try to string together multiple eliminations." msgE = "If you don’t have any good moves, if you can, try to take at least one territory to get cards for the round." msgF = "Attack with at least 3 attackers (meaning at least four units in the territory) for the best odds of success." msgG = "Consolidate your forces – if your attackers falls below 3, you reduce your odds of success." msgH = "When holding a continent, place troops at the borders rather than spreading throughout the continent." msgI = "Watch where your opponent fortifies his troops, it may tip you off to his next move." msgAr = [msgA,msgB, msgC, msgD, msgE, msgF, msgG, msgH, msgI] UI.makeButton(grey,250,40,500,50,'Here are some hints - hope they help!',45) down = 35 for i in range(len(msgAr)): UI.makeButton(grey,150,(120+(down)*i),700,30,msgAr[i],18) UI.makeButton(black,385,480,180,60,'',0) UI.makeButton(red,390,485,170,50,'Got it!',30) hint = True while hint: mouse = pygame.mouse.get_pos() click = pygame.mouse.get_pressed() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if (390) < mouse[0] < (390+170) and (480) < mouse[1] < (480+60): UI.makeButton(brightRed,390,485,170,50,'Got it!',30) if click[0] == 1: hint = False else: UI.makeButton(red,390,485,170,50,'Got it!',30) pygame.display.update() self.menu()