The entire source code for VillageWars 1.7.1 is displayed below, organized alphabetically by filename. Because of this, this webpage is extremely long. Use the table of contents to find what you are looking for.
VillageWars is constantly undergoing updates, so the code shown here might not be the most recent edition. Do NOT try to play the game by copying and pasting the following into python files and running them. This will not work because these files need the images as well to work properly.
main.py
import os, sys, json
import subprocess
with open('preferences.json', 'r') as fo:
preferences = json.loads(fo.read())
py = preferences.get('py', 'python')
path = preferences.get('path', [])
sys.path.extend(path)
missing_modules = []
try:
import pygame
except:
missing_modules.append('pygame')
try:
import requests
except:
missing_modules.append('requests')
try:
import bs4
except:
missing_modules.append('beautifulsoup4')
try:
import pymsgbox
except:
missing_modules.append('pymsgbox')
try:
import pyperclip
except:
missing_modules.append('pyperclip')
try:
import progress_bar
except:
missing_modules.append('progress_bar')
try:
import send2trash
except:
missing_modules.append('send2trash')
try:
import zipfile2
except:
missing_modules.append('zipfile2')
try:
import websockets
except:
missing_modules.append('websockets')
try:
fo = open('../version screenshots/version_info.json', 'r')
fo.close()
except OSError:
missing_modules.append('version_info.json')
os.chdir('src')
#pymsgbox.alert('*'.join(missing_modules))
#print(missing_modules)
if len(missing_modules) > 0:
os.system(py + ' -m setup ' + '*'.join(missing_modules))
else:
os.system(py + ' -m VillageWarsClient')
input()
src
The src
file folder contains most of the source code for VillageWars.
animations.py
import pygame
class Animation(pygame.sprite.Sprite):
def __init__(self, item):
super().__init__(self.gp)
self.frame = 0
self.len = 3
self.server = (item.server if hasattr(item, 'server') else item.channel.server)
self.size = 50
self.x = item.x
self.y = item.y
def __len__(self):
return self.len
def update(self):
self.frame += 1
if len(self) == self.frame:
self.kill()
else:
for p in self.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, self.size, self.size)
rect.center = (p.character.get_x(self), p.character.get_y(self))
if screen.colliderect(rect):
p.to_send.append({'action':'animation',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'name':self.__class__.__name__,
'frame':self.frame})
class Splash(Animation):
def __init__(self, balloon):
super().__init__(balloon)
self.size = 30
class Explosion(Animation):
def __init__(self, item):
super().__init__(item)
self.size = 64
class BAM(Animation):
def __init__(self, TNT):
super().__init__(TNT)
self.size = 360
self.len = 6
background.py
class Background():
def __init__(self, server):
self.server = server
self.x = 0
self.y = 0
def update(self):
for p in self.server.players:
if not p.pending:
p.to_send.append({'action':'draw_setting', 'coords':(p.character.get_x(self), p.character.get_y(self))})
balloon.py
import pygame
import toolbox as t
from animations import *
import random as r
class Balloon(pygame.sprite.Sprite):
def __init__(self, server, owner):
pygame.sprite.Sprite.__init__(self, self.gp)
self.server = server
self.owner = owner
self._owner = owner.channel.username
self.speed = owner.balloon_speed
self.x = owner.x
self.y = owner.y
self.angle = owner.angle
self.damage = owner.attack
self.knockback = owner.knockback
self.image = pygame.image.load('../assets/balloon.png')
self.type = ('normal' if self.damage < 20 else 'op')
if self.owner.shot_speed < 8:
self.type = ('speedy' if self.damage < 20 else 'speedy+op')
def update(self):
self.move()
if self.alive():
for p in self.server.players:
if not p.pending:
p.to_send.append({'action':'draw_balloon',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'angle':self.angle,
'type':self.type})
self.test_collide()
def test_collide(self):
result = False
obstacles = self.server.obs
if self.x > 7000 or self.x < -1000 or self.y > 4400 or self.y < -500:
self.kill()
return
self.rect = self.image.get_rect(center=(self.x, self.y))
for item in obstacles:
if hasattr(item, 'image') and item.image == 'barrel' and not item.sedentary:
continue
try:
if self.rect.colliderect(item.innerrect) and not (self.__class__ == Arrow and item.__class__.__name__ == 'ArcheryTower') and not (self.__class__ == Arrow and item.owner == self.owner):
try:
item.getHurt(self.damage, self.owner)
except:
item.getHurt(self.damage, self.owner, 0)
self.pop()
except:
pass
for item in self.server.bushes:
if self.rect.colliderect(item.innerrect) and not (self.__class__ == Arrow and item.owner == self.owner):
item.getHurt(self.damage, self.owner)
self.pop()
for p in self.server.players:
if not p.pending:
if self.rect.colliderect(p.character.rect) and p != self.owner.channel and p.character.dead == False:
if self.__class__ == Arrow:
result = p.character.getHurt(self.damage, self._owner, self.angle, self.knockback, '<Victim> was shot by <Attacker>')
else:
result = p.character.getHurt(self.damage, self.owner, self.angle, self.knockback)
if result == 'repelled':
bb = type(self)(self.server, p.character)
bb.damage = self.owner.attack
bb.knockback = self.owner.knockback
bb.angle = self.angle + 180 + r.randint(-20, 20)
bb.speed = self.owner.balloon_speed
self.kill()
if hasattr(bb, 'bb'):
bb.bb.damage = self.owner.attack
bb.bb.knockback = self.owner.knockback
bb.bb.angle = self.angle + 180 + r.randint(-20, 20)
bb.bb.speed = self.owner.balloon_speed
return
else:
self.pop()
for npc in self.server.NPCs:
if npc.__class__.__name__ == 'Robot':
if self.rect.colliderect(npc.rect) and not (self.owner == npc.player) and not npc.dead:
npc.getHurt(self.damage, self.angle, self.knockback)
self.pop()
for npc in self.server.event.NPCs:
if self.rect.colliderect(npc.rect):
result = npc.getHurt(self.owner, self.damage, self.angle, self.knockback)
if result and result[0] == 'repelled' and self.server.event.__class__.__name__ == 'BarbarianRaid':
BounceBalloon(self, result[1])
self.kill()
else:
self.pop()
def move(self):
dist = self.speed
while dist > 16:
x, y = t.getDir(self.angle, 16)
self.x += x
self.y += y
dist -= 16
self.test_collide()
#print(self.alive())
if not self.alive():
return
x, y = t.getDir(self.angle, dist)
self.x += x
self.y += y
def pop(self):
for p in self.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
screen.center = p.character.rect.center
if screen.colliderect(self.rect):
if self.type == 'normal' or self.type == 'speedy':
p.to_send.append({'action':'sound', 'sound':'splash'})
elif self.type == 'op' or self.type == 'speedy+op':
p.to_send.append({'action':'sound', 'sound':'opsplash'})
Splash(self)
self.kill()
class Arrow(Balloon):
def __init__(self, server=None, tower=None):
if tower.__class__.__name__ == 'Character':
self.bb = Balloon(server=server, owner=tower)
return None
Balloon.__init__(self, tower.server, tower.owner)
self.x = tower.innerrect.center[0]
self.y = tower.innerrect.center[1]
self.speed = tower.balloon_speed
self.angle = tower.angle
self.damage = tower.attack
self.knockback = tower.knockback
self._owner = tower.owner.channel.username + "'s Archery Tower"
self.type = 'normal'
class Bolt(pygame.sprite.Sprite):
def __init__(self, server=None, archer=None):
pygame.sprite.Sprite.__init__(self, Balloon.gp)
if archer.__class__.__name__ == 'Character':
self.server = archer.channel.server
self.speed = archer.balloon_speed
self.x = archer.x
self.y = archer.y
self.angle = archer.angle
self.damage = 10
self.knockback = 50
self.owner = archer
self.archer = None
else:
self.server = archer.event.server
self.speed = 17
self.x = archer.x
self.y = archer.y
self.angle = archer.angle
self.damage = 10
self.knockback = 50
self.owner = 'A Barbarian Archer'
self.archer = archer
self.image = pygame.image.load('../assets/balloon.png')
def update(self):
self.move()
if self.alive():
for p in self.server.players:
if not p.pending:
p.to_send.append({'action':'draw_balloon',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'angle':self.angle,
'type':'bolt'})
self.test_collide()
def test_collide(self):
obstacles = self.server.obs
if self.x > 7000 or self.x < -1000 or self.y > 4400 or self.y < -500:
self.kill()
return
self.rect = self.image.get_rect(center=(self.x, self.y))
for item in obstacles:
if self.rect.colliderect(item.innerrect):
item.getHurt(self.damage, self.owner)
self.pop()
elif item.isBuilding() and not (not self.archer and item.owner != self.owner.channel):
if self.rect.colliderect(item.rect):
item.getHurt(self.damage, self.owner)
self.pop()
for p in self.server.players:
if not (not self.archer and p.character == self.owner): # If not the player shooting the bolt
if not p.pending:
if self.rect.colliderect(p.character.rect) and p.character.dead == False:
if self.archer:
result = p.character.getHurt(self.damage, 'A Barbarian Archer', self.angle, self.knockback, msg='<Attacker> shot <Victim> and stole their gold and food.')
if p.character.dead and result != 'BAM':
self.archer.gold += p.character.gold
self.archer.food += p.character.food
p.character.gold = 0
p.character.food = 0
else:
result = p.character.getHurt(self.damage, self.owner, self.angle, self.knockback, msg='<Attacker> shot <Victim> with a barbarian crossbow.')
if result == 'repelled':
bb = type(self)(archer=p.character)
bb.speed = 17
bb.damage = 10
bb.knockback = 50
bb.angle = self.angle + 180 + r.randint(-20, 20)
self.kill()
return
else:
self.pop()
for npc in self.server.NPCs:
if npc.__class__.__name__ == 'Robot' and not (self.archer and npc.player == self.owner):
if self.rect.colliderect(npc.rect) and not npc.dead:
npc.getHurt(self.damage, self.angle, self.knockback)
self.pop()
if self.server.event.__class__.__name__ != 'BarbarianRaid' or not self.archer:
for npc in self.server.event.NPCs:
if self.rect.colliderect(npc.rect):
npc.getHurt(self.owner, self.damage, self.angle, self.knockback)
self.pop()
move = Balloon.move
def pop(self):
self.kill()
class BounceBalloon(pygame.sprite.Sprite):
def __init__(self, old_self, angle):
pygame.sprite.Sprite.__init__(self, Balloon.gp)
self.server = old_self.server
self.owner = 'A Barbarian'
self.speed = old_self.speed
self.x = old_self.x
self.y = old_self.y
self.angle = angle
self.damage = old_self.damage
self.knockback = old_self.knockback
self.mock_owner = old_self.owner
self.type = old_self.type
self.image = pygame.image.load('../assets/balloon.png')
def update(self):
self.move()
if self.alive():
for p in self.server.players:
if not p.pending:
p.to_send.append({'action':'draw_balloon',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'angle':self.angle,
'type':self.type})
self.test_collide()
def test_collide(self):
obstacles = self.server.obs
if self.x > 7000 or self.x < -1000 or self.y > 4400 or self.y < -500:
self.kill()
return
self.rect = self.image.get_rect(center=(self.x, self.y))
for item in obstacles:
if self.rect.colliderect(item.innerrect):
item.getHurt(self.damage, self.owner)
self.pop()
elif item.isBuilding():
if self.rect.colliderect(item.rect):
item.getHurt(self.damage, self.owner)
self.pop()
for p in self.server.players:
if not p.pending:
if self.rect.colliderect(p.character.rect) and p.character.dead == False:
result = p.character.getHurt(self.damage, self.owner, self.angle, self.knockback)
if result == 'repelled':
bb = Balloon(self.server, p.character)
bb.damage = self.damage
bb.knockback = self.knockback
bb.angle = self.angle + 180 + r.randint(-20, 20)
bb.speed = self.speed
self.kill()
return
else:
self.pop()
for npc in self.server.NPCs:
if npc.__class__.__name__ == 'Robot':
if self.rect.colliderect(npc.rect) and not npc.dead:
npc.getHurt(self.damage, self.angle, self.knockback)
self.pop()
move = Balloon.move
def pop(self):
for p in self.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
screen.center = p.character.rect.center
if screen.colliderect(self.rect):
p.to_send.append({'action':'sound', 'sound':'splash'})
Splash(self)
self.kill()
building.py
import pygame
import toolbox as t
import math
import random as r
from NPC import *
import os
#from InnPC import *
try:
DISHES = len(os.listdir('../assets/meals')) - 2
except:
DISHES = 1
class Building(pygame.sprite.Sprite):
dimensions = (600, 600)
def __init__(self, server, x, y, owner):
'''
owner must be client channel, not character.
'''
try:
pygame.sprite.Sprite.__init__(self, self.gp)
except:
pygame.sprite.Sprite.__init__(self, pygame.sprite.Group())
self.x = x
self.y = y
self.type = self.__class__.__qualname__
self.server = server
self.level = 1
self.owner = owner
self.max_health = self.health = 50
self.state = 'alive'
self.dimensions = type(self).dimensions
self.p = pygame.Surface((200, 200))
self.innerrect = self.p.get_rect(center=(x,y))
self.rect = pygame.Surface((50, 50)).get_rect(midtop=(self.innerrect.midbottom[0], self.innerrect.midbottom[1] + 110))
def post_init(self, rect):
self.dimensions = type(self).dimensions
self.dimensions = rect.size
self.dim_rect = rect
self.server.building_blocks.append(self.dim_rect)
self.server.obs.append(self)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Number of non-broken buildings', str(len(channel.get_buildings()))),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.Out)],
'simp':['Heal (5 food)', 'Out']}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'upgradable':False,
'4th_info':('Number of non-broken buildings', str(len(channel.get_buildings()))),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 gold)', 'Out']}
def update(self):
for p in self.server.players:
if not p.pending:
player = p.character
angle = t.getAngle(self.rect.x, self.rect.y, player.x, player.y)
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.dim_rect.size
rect.topleft = (p.character.get_x(self.dim_rect), p.character.get_y(self.dim_rect))
if screen.colliderect(rect):
p.to_send.append({'action':'draw_building',
'image':'house',
'coords':(player.get_x(self), player.get_y(self)),
'health':self.health,
'max_health':self.max_health,
'angle':angle,
'color':self.owner.color,
'dimensions':self.dimensions,
'type':self.type,
'state':self.state,
'level':self.level})
def getHurt(self, damage, attacker):
if self.health > 0 and attacker != self.owner.character:
self.health -= damage
if self.health < 1:
self.state = 'broken'
if attacker.__class__.__name__ == 'Character':
self.owner.message = attacker.channel.username + ' has broken one of your ' + self.type + 's.'
attacker.destroyed += 1
else:
self.owner.message = attacker + ' has broken one of your ' + self.type + 's.'
self.owner.message_count = 150
self.owner.message_color = (255,0,0)
self.health = 0
self.die()
for p in self.server.players:
screen = pygame.Rect(0, 0, 1000, 650)
screen.center = p.character.rect.center
if screen.colliderect(self.rect):
p.to_send.append({'action':'sound', 'sound':'building'})
def die(self):
pass
def isBuilding(self):
return True
def Out(self, character):
character.channel.in_window = False
character.shoot_cooldown = 20
character.channel.to_send.append({'action':'sound', 'sound':'cw'})
def heal(self, player):
if player != self.owner.character:
player.channel.message = "You can't heal someone else's building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
elif player.food > 4:
if self.health < self.max_health:
self.health += 10
if self.health > self.max_health:
self.health = self.max_health
player.channel.message = 'You just healed this building 10 health for 5 food.'
player.channel.message_count = 120
player.channel.message_color = (255,205,0)
player.food -= 5
else:
player.channel.message = 'This building is already at full health!'
player.channel.message_count = 150
player.channel.message_color = (50,50,255)
else:
player.channel.message = "You don't have enough food to heal this building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def clear(self, player):
self.Out(player)
if player.gold > 1:
player.channel.message = 'Cleared building for 2 gold'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 2
if self.dim_rect in self.server.building_blocks:
self.server.building_blocks.remove(self.dim_rect)
if self in self.server.obs:
self.server.obs.remove(self)
self.kill()
else:
player.channel.message = "You don't have enough gold to clear this building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
class CentralBuilding(Building):
dimensions = (675, 550)
def __init__(self, server, x, y, owner, rect=None):
Building.__init__(self, server, x, y, owner)
self.type = 'Central Building'
self.max_health = self.health = 420
self.dimensions = type(self).dimensions
self.info = ('The Central Building is for buying other buildings.', 'If all your buildings are destroyed, you will not respawn.')
if rect is None:
rect = pygame.Rect(0, 0, 675, 550)
rect.midtop = (x, y-round(self.p.get_height()/2))
self.post_init(rect)
def update(self):
Building.update(self)
if False: # Makes building move, lol
self.dim_rect.x += 3
self.rect.x += 3
self.x += 3
self.innerrect.x += 3
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Number of non-broken buildings', str(len(channel.get_buildings()))),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.buy_central_building), (2, self.buy_fitness_center), (3, self.buy_balloonist), (4, self.buy_farmers_guild), (5, self.buy_miners_guild), (6, self.buy_construction_site), (7, self.buy_restaurant), (8, self.buy_inn), (9, self.Out)],
'simp':['Heal (5 food)', 'Portable Central Building (10 gold, 10 food)', 'Fitness Center (50 food)', 'Balloonist (30 gold)', "Farmer's Guild (25 food)", "Miner's Guild (25 gold)", 'Construction Site (60 gold)', 'Restaurant (80 food)', 'Inn (100 food)', 'Out']}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'upgradable':False,
'health':(self.health, self.max_health),
'building':self,
'4th_info':('Number of non-broken buildings', str(len(channel.get_buildings()))),
'level':self.level,
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 gold)', 'Out']}
def buy_central_building(self, player):
if player.food > 9:
if player.gold > 9:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = PortableCentralBuilding
player.channel.message = 'You just bought a Portable Central Building for 10 gold and 10 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 10
player.food -= 10
else:
player.channel.message = "You don't have enough gold to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
else:
if player.gold > 9:
player.channel.message = "You don't have enough food to buy this!"
else:
player.channel.message = "You can't afford this building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'gold'
def buy_fitness_center(self, player):
if player.food > 49:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = FitnessCenter
player.channel.message = 'You just bought a Fitness Center for 50 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 50
else:
player.channel.message = "You don't have enough food to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'food'
def buy_farmers_guild(self, player):
if player.food > 24:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = FarmersGuild
player.channel.message = "You just bought a Farmer's Guild for 25 food."
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 25
else:
player.channel.message = "You don't have enough food to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'food'
def buy_miners_guild(self, player):
if player.gold > 24:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = MinersGuild
player.channel.message = "You just bought a Miner's Guild for 25 gold."
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 25
else:
player.channel.message = "You don't have enough gold to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'gold'
def buy_balloonist(self, player):
if player.gold > 29:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = Balloonist
player.channel.message = 'You just bought a Balloonist for 30 gold.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 30
else:
player.channel.message = "You don't have enough gold to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'gold'
def buy_construction_site(self, player):
if player.gold > 59:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = ConstructionSite
player.channel.message = 'You just bought a Construction Site for 60 gold.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 60
else:
player.channel.message = "You don't have enough gold to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'gold'
def buy_restaurant(self, player):
if player.food > 79:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = Restaurant
player.channel.message = 'You just bought a Restaurant for 80 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 80
else:
player.channel.message = "You don't have enough food to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'food'
def buy_inn(self, player):
yes = True
for b in player.channel.get_buildings():
if b.type == 'Inn':
yes = False
player.channel.message = 'You already have an Inn! You can only have one at a time.'
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
if yes:
if player.food > 99:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = Inn
player.channel.message = 'You just bought an Inn for 100 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 100
else:
player.channel.message = "You don't have enough food to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'food'
class PortableCentralBuilding(Building):
dimensions = (560, 560)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.type = 'Portable Central Building'
self.max_health = self.health = 110
self.dimensions = type(self).dimensions
self.info = ('This building works the same way as the regular Central Building,', 'so you can use it as a portable central building.')
self.post_init(rect)
def update(self):
Building.update(self)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Number of non-broken buildings', str(len(channel.get_buildings()))),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.buy_central_building), (2, self.buy_fitness_center), (3, self.buy_balloonist), (4, self.buy_farmers_guild), (5, self.buy_miners_guild), (6, self.buy_construction_site), (7, self.buy_restraunt), (8, self.buy_inn), (9, self.Out)],
'simp':['Heal (5 food)', 'Portable Central Building (10 gold, 10 food)', 'Fitness Center (50 food)', 'Balloonist (30 gold)', "Farmer's Guild (25 food)", "Miner's Guild (25 gold)", 'Construction Site (60 gold)', 'Restaurant (80 food)', 'Inn (100 food)', 'Out']}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'upgradable':False,
'health':(self.health, self.max_health),
'building':self,
'4th_info':('Number of non-broken buildings', str(len(channel.get_buildings()))),
'level':self.level,
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 gold)', 'Out']}
def buy_central_building(self, player):
if player.food > 9:
if player.gold > 9:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = PortableCentralBuilding
player.channel.message = 'You just bought a Portable Central Building for 10 gold and 10 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 10
player.food -= 10
else:
player.channel.message = "You don't have enough gold to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
else:
if player.gold > 9:
player.channel.message = "You don't have enough food to buy this!"
else:
player.channel.message = "You can't afford this building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'gold'
def buy_fitness_center(self, player):
if player.food > 49:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = FitnessCenter
player.channel.message = 'You just bought a Fitness Center for 50 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 50
else:
player.channel.message = "You don't have enough food to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'food'
def buy_inn(self, player):
yes = True
for b in player.channel.get_buildings():
if b.type == 'Inn':
yes = False
player.channel.message = 'You already have an Inn! You can only have one at a time.'
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
if yes:
if player.food > 99:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = Inn
player.channel.message = 'You just bought an Inn for 100 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 100
else:
player.channel.message = "You don't have enough food to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'food'
def buy_farmers_guild(self, player):
if player.food > 24:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = FarmersGuild
player.channel.message = "You just bought a Farmer's Guild for 25 food."
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 25
else:
player.channel.message = "You don't have enough food to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'food'
def buy_miners_guild(self, player):
if player.gold > 24:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = MinersGuild
player.channel.message = "You just bought a Miner's Guild for 25 gold."
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 25
else:
player.channel.message = "You don't have enough gold to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'gold'
def buy_balloonist(self, player):
if player.gold > 29:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = Balloonist
player.channel.message = 'You just bought a Balloonist for 30 gold.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 30
else:
player.channel.message = "You don't have enough gold to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'gold'
def buy_construction_site(self, player):
if player.gold > 59:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = ConstructionSite
player.channel.message = 'You just bought a Construction Site for 60 gold.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 60
else:
player.channel.message = "You don't have enough gold to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'gold'
def buy_restraunt(self, player):
if player.food > 79:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = Restaurant
player.channel.message = 'You just bought a Restaurant for 80 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 80
else:
player.channel.message = "You don't have enough food to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'food'
class RunningTrack(Building):
dimensions = (700, 620)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building increases your speed! Upgrade it to increase it', 'even more. (You can only have one Running Track at a time)')
self.type = 'Running Track'
self.health = self.max_health = 180
self.dimensions = type(self).dimensions
self.owner.character.speed += 3
self.owner.character.moving += 3
self.upgrade_cost = 90
self.post_init(rect)
def level_up(self, player):
if self.level == 3:
return
if player.food > self.upgrade_cost - 1:
self.level += 1
self.owner.character.speed += 3
self.owner.character.moving += 3
player.channel.message = 'You upgraded this Running Track to level ' + str(self.level) + ' for ' + str(self.upgrade_cost) + ' food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= self.upgrade_cost
self.upgrade_cost += 30
self.health = self.max_health = self.max_health + 40
else:
player.channel.message = "You don't have enough food to upgrade this building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
if self.level < 3:
channel.window = {'text':self.info,
'4th_info':('Speed', str(self.owner.character.speed)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.level_up), (1, self.heal), (2, self.Out)],
'simp':['Upgrade (' + str(self.upgrade_cost) + ' food)', 'Heal (5 food)', 'Out']}
else:
channel.window = {'text':self.info,
'4th_info':('Speed', str(self.owner.character.speed)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.Out)],
'simp':['Heal (5 food)', 'Out']}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'4th_info':('Speed', str(self.owner.character.speed)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.clear), (1, self.heal), (2, self.Out)],
'simp':['Clear (2 gold)', 'Out']}
def getHurt(self, damage, attacker):
if self.health > 0 and attacker != self.owner.character:
self.health -= damage
if self.health < 1:
self.state = 'broken'
if attacker.__class__.__name__ == 'Character':
self.owner.message = attacker.channel.username + ' has broken one of your ' + self.type + 's.'
attacker.destroyed += 1
else:
self.owner.message = attacker + ' has broken one of your ' + self.type + 's.'
self.owner.message_count = 150
self.owner.message_color = (255,0,0)
self.health = 0
self.die()
for p in self.server.players:
screen = pygame.Rect(0, 0, 1000, 650)
screen.center = p.character.rect.center
if screen.colliderect(self.rect):
p.Send({'action':'sound', 'sound':'building'})
self.owner.character.speed = 8
self.owner.character.moving = 8
class Gym(Building):
dimensions = (700, 620)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building increases your resistance! Upgrade it to increase it', 'even more. (You can only have one Gym at a time)')
self.type = 'Gym'
self.health = self.max_health = 180
self.dimensions = type(self).dimensions
self.owner.character.strength += 2
self.upgrade_cost = 90
self.post_init(rect)
def level_up(self, player):
if self.level == 3:
return
if player.food > self.upgrade_cost - 1:
self.level += 1
self.owner.character.strength += 2
player.channel.message = 'You upgraded this Gym to level ' + str(self.level) + ' for ' + str(self.upgrade_cost) + ' food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= self.upgrade_cost
self.upgrade_cost += 30
self.health = self.max_health = self.max_health + 40
else:
player.channel.message = "You don't have enough food to upgrade this building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
if self.level < 3:
channel.window = {'text':self.info,
'4th_info':('Resistance', str(self.owner.character.strength)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.level_up), (1, self.heal), (2, self.Out)],
'simp':['Upgrade (' + str(self.upgrade_cost) + ' food)', 'Heal (5 food)', 'Out']}
else:
channel.window = {'text':self.info,
'4th_info':('Resistance', str(self.owner.character.strength)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.Out)],
'simp':['Heal (5 food)', 'Out']}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'4th_info':('Resistance', str(self.owner.character.strength)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 gold)', 'Out']}
def getHurt(self, damage, attacker):
if self.health > 0 and attacker != self.owner.character:
self.health -= damage
if self.health < 1:
self.state = 'broken'
if attacker.__class__.__name__ == 'Character':
self.owner.message = attacker.channel.username + ' has broken one of your ' + self.type + 's.'
attacker.destroyed += 1
else:
self.owner.message = attacker + ' has broken one of your ' + self.type + 's.'
self.owner.message_count = 150
self.owner.message_color = (255,0,0)
self.health = 0
self.die()
for p in self.server.players:
screen = pygame.Rect(0, 0, 1000, 650)
screen.center = p.character.rect.center
if screen.colliderect(self.rect):
p.Send({'action':'sound', 'sound':'building'})
self.owner.character.strength = 0
class HealthCenter(Building):
dimensions = (700, 620)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building increases your maximum health! Upgrade it to increase it', 'even more. (You can only have one Health Center at a time)')
self.type = 'Health Center'
self.health = self.max_health = 180
self.dimensions = type(self).dimensions
self.owner.character.max_health += 30
self.owner.character.health += 30
self.upgrade_cost = 90
self.post_init(rect)
def level_up(self, player):
if self.level == 3:
return
if player.food > self.upgrade_cost - 1:
self.level += 1
self.owner.character.max_health += 30
self.owner.character.health += 30
player.channel.message = 'You upgraded this Health Center to level ' + str(self.level) + ' for ' + str(self.upgrade_cost) + ' food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= self.upgrade_cost
self.upgrade_cost += 30
self.health = self.max_health = self.max_health + 40
else:
player.channel.message = "You don't have enough food to upgrade this building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
if self.level < 3:
channel.window = {'text':self.info,
'4th_info':('Player health', ('%s/%s' % (self.owner.character.health, self.owner.character.max_health))),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.level_up), (1, self.heal), (2, self.Out)],
'simp':['Upgrade (' + str(self.upgrade_cost) + ' food)', 'Heal (5 food)', 'Out']}
else:
channel.window = {'text':self.info,
'4th_info':('Player health', ('%s/%s' % (self.owner.character.health, self.owner.character.max_health))),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.Out)],
'simp':['Heal (5 food)', 'Out']}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'4th_info':('Player health', ('%s/%s' % (self.owner.character.health, self.owner.character.max_health))),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 gold)', 'Out']}
def getHurt(self, damage, attacker):
if self.health > 0 and attacker != self.owner.character:
self.health -= damage
if self.health < 1:
self.state = 'broken'
if attacker.__class__.__name__ == 'Character':
self.owner.message = attacker.channel.username + ' has broken one of your ' + self.type + 's.'
attacker.destroyed += 1
else:
self.owner.message = attacker + ' has broken one of your ' + self.type + 's.'
self.owner.message_count = 150
self.owner.message_color = (255,0,0)
self.health = 0
self.die()
for p in self.server.players:
screen = pygame.Rect(0, 0, 1000, 650)
screen.center = p.character.rect.center
if screen.colliderect(self.rect):
p.Send({'action':'sound', 'sound':'building'})
self.owner.character.max_health = 100
if self.owner.character.health > 100:
self.owner.character.health = 100
class FitnessCenter(Building):
dimensions = (585, 600)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building lets you buy the 3 fitness', 'buildings: Running Track, Gym and Health Center.')
self.type = 'Fitness Center'
self.health = self.max_health = 140
self.dimensions = type(self).dimensions
self.post_init(rect)
def buy_running_track(self, player):
yes = True
for b in player.channel.get_buildings():
if b.type == 'Running Track':
yes = False
player.channel.message = 'You already have a Running Track! You can only have one at a time.'
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
if yes:
if player.food > 74:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = RunningTrack
player.channel.message = 'You just bought a Running Track for 75 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 75
else:
player.channel.message = "You don't have enough food to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'food'
def buy_gym(self, player):
yes = True
for b in player.channel.get_buildings():
if b.type == 'Gym':
yes = False
player.channel.message = 'You already have a Gym! You can only have one at a time.'
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
if yes:
if player.food > 74:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = Gym
player.channel.message = 'You just bought a Gym for 75 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 75
else:
player.channel.message = "You don't have enough food to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'food'
def buy_health_center(self, player):
yes = True
for b in player.channel.get_buildings():
if b.type == 'Health Center':
yes = False
player.channel.message = 'You already have a Health Center! You can only have one at a time.'
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
if yes:
if player.food > 74:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = HealthCenter
player.channel.message = 'You just bought a Health Center for 75 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 75
else:
player.channel.message = "You don't have enough food to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
player.spence = 'food'
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Number of fitness buildings', ('%s/3' % len([b for b in self.owner.get_buildings() if b.type in ('Health Center', 'Gym', 'Running Track')]))),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.buy_running_track), (2, self.buy_gym), (3, self.buy_health_center), (4, self.Out)],
'simp':['Heal (5 food)', 'Running Track (75 food)', 'Gym (75 food)', 'Health Center (75 food)', 'Out']}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'upgradable':False,
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'4th_info':('Number of fitness buildings', ('%s/3' % len([b for b in self.owner.get_buildings() if b.type in ('Health Center', 'Gym', 'Running Track')]))),
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 gold)', 'Out']}
class Balloonist(Building):
dimensions = (500, 495)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building lets you upgrade your attack stats.', '')
self.type = 'Balloonist'
self.health = self.max_health = 120
self.dimensions = type(self).dimensions
self.upgrade_cost = 50
self.post_init(rect)
def level_up(self, player):
if player.gold > self.upgrade_cost - 1:
self.level += 1
player.channel.message = 'You upgraded this Balloonist to level ' + str(self.level) + ' for ' + str(self.upgrade_cost) + ' gold.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= self.upgrade_cost
self.upgrade_cost += 20
self.health = self.max_health = self.max_health + 50
else:
player.channel.message = "You don't have enough gold to upgrade this building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Attack Damage', str(self.owner.character.attack)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.level_up), (1, self.heal), (2, self.upgrade_balloon_damage), (3, self.upgrade_balloon_speed), (4, self.Out)],
'simp':['Upgrade (' + str(self.upgrade_cost) + ' gold)', 'Heal (5 food)', ' + Balloon Attack (' + str(channel.character.damage_cost) + ' gold)', ' + Balloon Speed (' + str(channel.character.speed_cost) + ' gold)', 'Out']}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'4th_info':('Attack Damage', str(self.owner.character.attack)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 gold)', 'Out']}
def upgrade_balloon_speed(self, player):
if player.gold > player.speed_cost - 1:
player.balloon_speed += 3
player.knockback += 8
player.channel.message = "You upgraded your balloons' speed for " + str(self.owner.character.speed_cost) + " gold."
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= player.speed_cost
player.speed_cost += 2
else:
player.channel.message = "You don't have enough gold to upgrade your balloons' speed!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def upgrade_balloon_damage(self, player):
if player.gold > player.damage_cost - 1:
player.attack += 1
player.channel.message = "You upgraded your attack for " + str(self.owner.character.damage_cost) + " gold."
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= player.damage_cost
player.damage_cost += 10
else:
player.channel.message = "You don't have enough gold to upgrade your attack!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
class FarmersGuild(Building):
dimensions = (600, 500)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building sends farmers out to collect wheat for you.', '')
self.type = "Farmer's Guild"
self.health = self.max_health = 140
self.dimensions = type(self).dimensions
self.farmer = Farmer(self)
self.post_init(rect)
def getHurt(self, damage, attacker):
if self.health > 0 and attacker != self.owner.character:
self.health -= damage
if self.health < 1:
self.state = 'broken'
if attacker.__class__.__name__ == 'Character':
self.owner.message = attacker.channel.username + ' has broken one of your ' + self.type + 's.'
attacker.destroyed += 1
else:
self.owner.message = attacker + ' has broken one of your ' + self.type + 's.'
self.owner.message_count = 150
self.owner.message_color = (255,0,0)
self.health = 0
self.die()
for p in self.server.players:
screen = pygame.Rect(0, 0, 1000, 650)
screen.center = p.character.rect.center
if screen.colliderect(self.rect):
p.Send({'action':'sound', 'sound':'building'})
for farmer in self.server.NPCs:
if farmer.building == self:
farmer.kill()
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Food Production Rate', str(1250 - self.farmer.farm.production)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.Out)],
'simp':['Heal (5 food)', 'Out']}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'4th_info':('Food Production Rate', str(1250 - self.farmer.farm.production)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 gold)', 'Out']}
class MinersGuild(Building):
dimensions = (500, 600)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building sends miners out to mine gold for you.', '')
self.type = "Miner's Guild"
self.health = self.max_health = 140
self.dimensions = type(self).dimensions
self.miner = Miner(self)
self.post_init(rect)
def getHurt(self, damage, attacker):
if self.health > 0 and attacker != self.owner.character:
self.health -= damage
if self.health < 1:
self.state = 'broken'
if attacker.__class__.__name__ == 'Character':
self.owner.message = attacker.channel.username + ' has broken one of your ' + self.type + 's.'
attacker.destroyed += 1
else:
self.owner.message = attacker + ' has broken one of your ' + self.type + 's.'
self.owner.message_count = 150
self.owner.message_color = (255,0,0)
self.health = 0
self.die()
for p in self.server.players:
screen = pygame.Rect(0, 0, 1000, 650)
screen.center = p.character.rect.center
if screen.colliderect(self.rect):
p.Send({'action':'sound', 'sound':'building'})
for miner in self.server.NPCs:
if miner.building == self:
miner.kill()
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Gold Discovery Rate', str(1250 - self.miner.farm.production)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.Out)],
'simp':['Heal (5 food)', 'Out']}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'4th_info':('Gold Discovery Rate', str(1250 - self.miner.farm.production)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 gold)', 'Out']}
def builder(b, p, has_builder):
if b.isBuilding(object()):
dimensions = b.dimensions
if has_builder:
dimensions = (b.dimensions[0]*0.8, b.dimensions[1]*0.8)
x, y = p.x, p.y - 140
image = pygame.Surface((200, 200))
width, height = dimensions
rect = pygame.Rect(0, 0, width, height)
rect.midtop = (x, y-round(image.get_height()/2))
else:
x, y = p.x, p.y - 240
surf = pygame.Surface((360, 360))
rect = surf.get_rect(center=(x, y))
if rect.left < 0 or rect.right > 6000 or rect.top < 0 or rect.bottom > 3900:
return False, rect
for obs in p.channel.server.building_blocks:
if rect.colliderect(obs):
return False, rect
return True, rect
class ConstructionSite(Building):
dimensions = (560, 560)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building lets you buy defences for your village. Crates, Gates, Archery Towers,', 'Robot Factories...')
self.type = 'Construction Site'
self.health = self.max_health = 160
self.dimensions = type(self).dimensions
self.upgradable = True
self.post_init(rect)
def buy_crate(self, player):
if player.food > 1:
player.channel.message = 'You bought a crate for 2 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 2
player.crates += 1
else:
player.channel.message = "You don't have enough food for this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def buy_gate(self, player):
if player.gold > 39:
player.channel.message = 'You bought a gate for 40 gold.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 40
player.channel.text = 'Press x to place gate'
else:
player.channel.message = "You don't have enough gold for this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def buy_tnt(self, player):
if player.gold > 99:
if player.food > 99:
player.channel.message = 'You bought TNT for 100 gold and 100 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 100
player.food -= 100
player.channel.text = 'Press x to place TNT'
else:
player.channel.message = "You don't have enough food for this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
else:
if player.food > 99:
player.channel.message = "You don't have enough gold for this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
else:
player.channel.message = "You can't afford this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def buy_archery_tower(self, player):
if player.food > 19:
if player.gold > 109:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = ArcheryTower
player.channel.message = 'You just bought an Archery Tower for 110 gold and 20 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 110
player.food -= 20
player.spence = 'gold'
else:
player.channel.message = "You don't have enough gold to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
else:
if player.gold > 109:
player.channel.message = "You don't have enough food to buy this!"
else:
player.channel.message = "You can't afford an Archery Tower!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def level_up(self, player):
if player.gold > 29:
self.level = 2
player.channel.message = 'You upgraded this Construction Site to level 2 for 30 gold.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 30
self.upgradable = False
self.health = self.max_health = 200
else:
player.channel.message = "You don't have enough gold to upgrade this building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def buy_robot_factory(self, player):
if player.food > 4:
if player.gold > 114:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = RobotFactory
player.channel.message = 'You just bought a Robot Factory for 115 gold and 5 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 115
player.food -= 5
player.spence = 'gold'
else:
player.channel.message = "You don't have enough gold to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
else:
if player.gold > 114:
player.channel.message = "You don't have enough food to buy this!"
else:
player.channel.message = "You can't afford this building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def buy_barrel_maker(self, player):
if player.food > 64:
if player.gold > 49:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = BarrelMaker
player.channel.message = 'You just bought a Barrel Maker for 50 gold and 65 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 50
player.food -= 65
player.spence = 'food'
else:
player.channel.message = "You don't have enough gold to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
else:
if player.gold > 49:
player.channel.message = "You don't have enough food to buy this!"
else:
player.channel.message = "You can't afford this building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
if self.upgradable:
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Upgraded', 'False'),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.level_up), (1, self.heal), (2, self.buy_crate), (3, self.buy_gate), (4, self.buy_tnt), (5, self.Out)],
'simp':['Upgrade (30 gold)', 'Heal (5 food)', 'Crate (2 food)', 'Gate (40 gold)', 'TNT (100 gold, 100 food)', 'Out']}
else:
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Upgraded', 'True'),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.buy_crate), (2, self.buy_gate), (3, self.buy_tnt), (4, self.buy_archery_tower), (5, self.buy_robot_factory), (6, self.buy_barrel_maker), (7, self.Out)],
'simp':['Heal (5 food)', 'Crate (2 food)', 'Gate (40 gold)', 'TNT (100 gold, 100 food)', 'Archery Tower (110 gold, 20 food)', 'Robot Factory (115 gold, 5 food)', 'Barrel Maker (50 gold, 65 food)', 'Out']}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'4th_info':('Upgraded', str(self.level == 2)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 gold)', 'Out']}
class Restaurant(Building):
dimensions = (600, 580)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building lets you buy meals, which heal you when you eat them.', '')
self.type = 'Restaurant'
self.health = self.max_health = 220
self.dimensions = type(self).dimensions
self.post_init(rect)
def buy_meal(self, player):
if player.food > 11:
if player.meal:
player.channel.message = "You already have a meal! Eat it before buying another one."
player.channel.message_count = 150
player.channel.message_color = (0,0,255)
else:
player.meal = True
player.meal_type = r.randrange(DISHES)
player.channel.message = "You bought a meal for 12 food."
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 12
else:
player.channel.message = "You don't have enough food to buy a meal!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def dine_in(self, player):
if player.food > 5:
if player.meal:
player.channel.message = "You already have a meal! Eat it before ordering one."
player.channel.message_count = 150
player.channel.message_color = (0,0,255)
else:
player.channel.message = "You ate a meal for 6 food."
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 6
player.dine_in()
else:
player.channel.message = "You don't have enough food to order a meal!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Need meal', ('no' if channel.character.meal else 'yes')),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.buy_meal), (2, self.dine_in), (3, self.Out)],
'simp':['Heal (5 food)', 'Take out (12 food)', 'Order meal (6 food)', 'Out']}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'upgradable':False,
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'4th_info':('Need meal', ('no' if channel.character.meal else 'yes')),
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 gold)', 'Out']}
class RobotFactory(Building):
dimensions = (504, 500)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building sends out several little robots who attack', 'other players. It\'s a good way to defend your village!')
self.type = 'Robot Factory'
self.health = self.max_health = 120
self.dimensions = type(self).dimensions
self.post_init(rect)
Robot(self)
Robot(self)
Robot(self)
self.num_bots = 3
def level_up(self, player):
if player.gold > 39:
self.level += 1
player.channel.message = 'You upgraded this Robot Factory to level ' + str(self.level) + ' for 40 gold.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 40
self.upgradable = False
if self.max_health < 320: self.max_health += 50
self.health = self.max_health
Robot(self)
self.num_bots += 1
else:
player.channel.message = "You don't have enough gold to upgrade this building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Robots', str(self.num_bots)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.level_up), (2, self.Out)],
'simp':['Heal (5 food)', 'Upgrade (40 gold)', 'Out']}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'upgradable':False,
'health':(self.health, self.max_health),
'building':self,
'4th_info':('Robots', str(self.num_bots)),
'level':self.level,
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 gold)', 'Out']}
def die(self):
for npc in self.server.NPCs:
if type(npc).__name__ == 'Robot' and npc.factory == self:
npc.kill()
from InnPC import *
class Inn(Building):
dimensions = (550, 490)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building welcomes different NPCs that can trade with you.', '')
self.type = 'Inn'
self.health = self.max_health = 240
self.dimensions = type(self).dimensions
self.NPC = None
self.count = r.randint(250, 750)
self.post_init(rect)
def level_up(self, player):
if player.food > 99:
self.level = 2
player.channel.message = 'You upgraded this Inn to level 2 for 100 food.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 100
self.upgradable = False
self.max_health = 340
self.health = 340
else:
player.channel.message = "You don't have enough food to upgrade this building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
if self.NPC:
if self.level == 1:
channel.window = {'text':self.info,
'4th_info':('Hosting', self.NPC.type),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.level_up), (2, self.kick_npc), (3, self.build_house), (4, self.Out)],
'simp':['Heal (5 food)', 'Upgrade (100 food)', 'Kick %s (free)' % (self.NPC.type), 'Build the %s a house (%s gold, %s food)' % (self.NPC.type, self.NPC.cost[0], self.NPC.cost[1]), 'Out']}
else:
channel.window = {'text':self.info,
'4th_info':('Hosting', self.NPC.type),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.kick_npc), (2, self.build_house), (3, self.Out)],
'simp':['Heal (5 food)', 'Kick %s (free)' % (self.NPC.type), 'Build the %s a house (%s gold, %s food)' % (self.NPC.type, self.NPC.cost[0], self.NPC.cost[1]), 'Out']}
else:
if self.level == 1:
channel.window = {'text':self.info,
'4th_info':('Hosting', 'Nobody'),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.level_up), (2, self.Out)],
'simp':['Heal (5 food)', 'Upgrade (100 food)', 'Out']}
else:
channel.window = {'text':self.info,
'4th_info':('Hosting', 'Nobody'),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.Out)],
'simp':['Heal (5 food)', 'Out']}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'upgradable':False,
'health':(self.health, self.max_health),
'building':self,
'4th_info':('Hosting', ('Nobody' if self.NPC is None else self.NPC.type)),
'level':self.level,
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 gold)', 'Out']}
def update(self):
super().update()
if self.state != 'broken':
if self.NPC is not None:
self.NPC.update()
else:
if self.server.event.__class__.__name__ != 'BarbarianRaid':
self.count -= 1
if self.count == 0:
self.NPC = get_innpc(self)
def kick_npc(self, player):
if player.channel == self.owner:
name = self.NPC.type
self.NPC.depart()
player.channel.message = 'You have kicked the %s.' % name
player.channel.message_color = (128,0,128)
else:
player.channel.message = "This isn't your Inn!"
player.channel.message_count = 160
player.channel.message_color = (255,0,0)
self.Out(player)
def build_house(self, player):
if player == self.owner.character:
if player.food > self.NPC.cost[1]:
if player.gold > self.NPC.cost[0]:
player.channel.text = 'Right click to place building'
player.channel.build_to_place = self.NPC.building
NPC = self.NPC
self.NPC.depart()
player.channel.message = 'You just bought the %s a house for %s gold and %s food.' % (NPC.type, NPC.cost[0], NPC.cost[1])
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= NPC.cost[0]
player.food -= NPC.cost[1]
player.spence = ('gold' if NPC.cost[0] >= NPC.cost[1] else 'food')
else:
player.channel.message = "You don't have enough gold to buy this!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
else:
if player.gold > self.NPC.cost[0]:
player.channel.message = "You don't have enough food to buy this!"
else:
player.channel.message = "You can't afford this building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
else:
player.channel.message = "This isn't your Inn!"
player.channel.message_count = 160
player.channel.message_color = (255,0,0)
self.Out(player)
class BarrelMaker(Building):
dimensions = (670, 440)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building lets you buy barrels!! Z to hide. Z+Click to throw.', '(: (: (: (: (: (: (: (:')
self.type = 'Barrel Maker'
self.health = self.max_health = 250
self.upgrade_cost = 100
self.post_init(rect)
def level_up(self, player):
if player.gold > self.upgrade_cost - 1:
self.level += 1
player.channel.message = 'You upgraded this Barrel Maker to level ' + str(self.level) + ' for ' + str(self.upgrade_cost) + ' gold.'
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= self.upgrade_cost
self.upgrade_cost += 20
if self.level < 15:
self.health = self.max_health = self.max_health + 20
else:
player.channel.message = "You don't have enough gold to upgrade this building!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def buy_barrel(self, player):
if player.food > 16:
if player.barrel_health > 0:
player.channel.message = "You already have a barrel! Get rid of it before buying a new one."
player.channel.message_count = 150
player.channel.message_color = (0,0,255)
else:
player.channel.message = "You bought a barrel! (17 food)"
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.food -= 17
player.barrel_health = player.barrel_max_health = 10 + (5 * self.level)
player.explosive = False
else:
player.channel.message = "You don't have enough food to buy a barrel!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def buy_barrel_tnt(self, player):
if player.gold > 149:
if player.barrel_health > 0:
player.channel.message = "You already have a barrel! Get rid of it before buying a NEW one."
player.channel.message_count = 150
player.channel.message_color = (0,0,255)
else:
player.channel.message = "You bought an explosive barrel! (150 gold)"
player.channel.message_count = 150
player.channel.message_color = (255,205,0)
player.gold -= 150
player.barrel_health = player.barrel_max_health = 10 + (5 * self.level)
player.explosive = True
else:
player.channel.message = "You don't have enough gold to buy this quality barrel!"
player.channel.message_count = 150
player.channel.message_color = (255,0,0)
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Barrel Health', str(channel.character.barrel_health)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.level_up), (1, self.heal), (2, self.buy_barrel), (3, self.buy_barrel_tnt), (4, self.Out)],
'simp':['Upgrade (%s gold)' % self.upgrade_cost, 'Heal (5 food)', 'Barrel (17 food)', 'Explosive Barrel (150 gold)', 'Out']}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'upgradable':False,
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'4th_info':('Barrel Health', str(channel.character.barrel_health)),
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 gold)', 'Out']}
__ALL__ = ['CentralBuilding', 'PortableCentralBuilding', 'FitnessCenter', 'Balloonist', 'Gym', 'RunningTrack', 'HealthCenter', 'BarrelMaker', 'ConstructionSite', 'RobotFactory', 'Restaurant', 'MinersGuild', 'FarmersGuild', 'Inn']
events.py
import pygame
from random import *
import toolbox as t
from balloon import Bolt
import InnPC
class Event():
def __init__(self, server):
self.server = server
self.NPCs = []
def update(self):
pass
class BarbarianRaid():
def __init__(self, server, num=None, spawn=None):
self.server = server
self.server.event = self
for p in server.players:
for b in p.get_buildings():
if b.__class__.__name__ == 'Inn':
if b.NPC:
b.NPC.depart()
if not num:
self.num_barbarians = randint(4, 7)
for p in self.server.playing:
self.num_barbarians += 2
else:
self.num_barbarians = num
if spawn is None:
self.spawn = choice(['North', 'East', 'South', 'West'])
else:
self.spawn = spawn
for p in self.server.players:
p.message = 'A tribe of %s barbarians is aproaching from the %s!' % (self.num_barbarians, self.spawn)
p.message_color = (128,0,128)
p.message_count = 160
self.barbarians = []
self.NPCs = self.barbarians
self.leader = BarbarianLeader(self)
for b in range(self.num_barbarians - 1):
Barbarian(self)
for p in self.server.players:
if not p.pending:
p.Send({'action':'music_change', 'music':'barbarianraid'})
def end(self, attacker=None):
self.barbarians.clear()
for p in self.server.players:
if not p.pending:
p.Send({'action':'music_change', 'music':'village'})
if attacker:
for b in attacker.channel.get_buildings():
if b.__class__.__name__ == 'Inn':
npcs = [InnPC.Retired_barbarian, InnPC.Adventurer]
bds = attacker.channel.get_buildings()
for NPC in npcs[:]:
if NPC.building in [bd.__class__ for bd in bds]:
npcs.remove(NPC)
if npcs:
b.NPC = choice(npcs)(b)
self.server.event = Event(self.server)
def get_coords(self, r=240):
coords = {'North':(3000, 400),
'South':(3000, 3500),
'East':(5600, 1800),
'West':(400, 1800)
}
x, y = coords[self.spawn]
starting = True
while x < 50 or x > 5950 or y < 50 or y > 3850 or starting:
x += randint(-r, r)
y += randint(-r, r)
starting = False
for b in self.barbarians:
if b.rect.colliderect(b.surf.get_rect(center=(x, y))):
return self.get_coords(r=r+100)
return x, y
def update(self):
if True:#try:
for b in self.barbarians:
b.update()
#except:
#self.end()
def Barbarian(event):
eval(choice(['BarbarianArcher', 'BarbarianSwordsman', 'BarbarianSwordsman']) + '(event)')
class BarbarianLeader():
def __init__(self, event):
self.hurt = 0
self.shield_count = 0
self.shield_angle = 0
self.speed = 2
self.resistance = 2
self.health = 100
self.angle = 0
self.touching = False
self.event = event
self.surf = pygame.Surface((50, 50))
self.rect = self.surf.get_rect(center=(0, 0))
self.x, self.y = self.event.get_coords()
self.event.barbarians.append(self)
self.surf = pygame.Surface((50, 50))
self.rect = self.surf.get_rect(center=(self.x, self.y))
for p in self.event.server.playing:
self.resistance += 1.5
@property
def innerrect(self):
return self.rect
def explode(self, player, tnt):
self.getHurt(player, 60, t.getAngle(tnt.x, tnt.y, self.x, self.y), 120)
def update(self):
if self.hurt:
self.hurt -= 1
if self.shield_count:
self.shield_count -= 1
touching = False
for ob in self.event.server.obs:
if self.rect.colliderect(ob.innerrect):
touching = True
if not self.touching:
self.getHurt(None, 12, self.angle + 180, 100)
self.touching = touching
maxdist = 10000
player = None
playerdist = maxdist
for p in self.event.server.players:
if not p.pending and not p.character.dead:
if t.getDist(self.x, self.y, p.character.x, p.character.y) < maxdist:
maxdist = t.getDist(self.x, self.y, p.character.x, p.character.y)
player = p
playerdist = maxdist
if player == None:
for p in self.event.server.players:
if not p.pending:
p.to_send.append({'action':'draw_barbarian',
'type':'leader',
'hurt':self.hurt,
'coords':(p.character.get_x(self), p.character.get_y(self)),
'angle':self.angle,
'health':self.health,
'shield':(self.shield_angle if self.shield_count else None)})
return
self.angle = t.getAngle(self.x, self.y, player.character.x, player.character.y)
if playerdist < 400:
self.speed = 1
else:
self.speed = 2
x, y = t.getDir(self.angle, total=self.speed)
self.x += x
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.event.server.obs + self.event.barbarians:
if rect.colliderect(ob.innerrect) and ob != self:
if not self.touching:
self.x -= x
self.y += y
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.event.server.obs + self.event.barbarians:
if rect.colliderect(ob.innerrect) and ob != self:
if not self.touching:
self.y -= y
self.rect = self.surf.get_rect(center=(self.x, self.y))
for p in self.event.server.players:
if not p.pending:
if p.character.rect.colliderect(self.rect) and not p.character.dead:
result = p.character.getHurt(10, 'The Barbarian Leader', self.angle, 50)
if p.character.dead and result != 'BAM':
p.character.gold = 0
p.character.food = 0
for p in self.event.server.players:
if not p.pending:
p.to_send.append({'action':'draw_barbarian',
'type':'leader',
'hurt':self.hurt,
'coords':(p.character.get_x(self), p.character.get_y(self)),
'angle':self.angle,
'health':self.health,
'shield':(self.shield_angle if self.shield_count else None)})
def getHurt(self, attacker, damage, angle, knockback):
if randint(0, 2) < 2 and attacker != self:
self.shield_angle = angle + 180
self.shield_count = 20
for p in self.event.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.rect.size
rect.topleft = (p.character.get_x(self.rect), p.character.get_y(self.rect))
if screen.colliderect(rect):
p.to_send.append({'action':'sound','sound':'bump'})
return ('repelled', self.shield_angle + randint(-20, 20))
else:
x, y = t.getDir(angle, total=(self.speed+knockback))
self.x += x
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.event.server.obs + self.event.barbarians:
if rect.colliderect(ob.innerrect) and ob != self:
if not self.touching:
self.x -= x
self.y += y
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.event.server.obs + self.event.barbarians:
if rect.colliderect(ob.innerrect) and ob != self:
if not self.touching:
self.y -= y
self.hurt = 10
self.rect = self.surf.get_rect(center=(self.x, self.y))
self.health -= damage - self.resistance
if self.health <= 0:
if self in self.event.barbarians:
self.event.barbarians.remove(self)
self.health = 0
self.event.end(attacker)
self.event.server.event = Event(self.event.server)
for p in self.event.server.players:
if not p.pending:
p.message = 'The Barbarian tribe has been defeated.'
p.message_color = (128,0,128)
p.message_count = 160
try:
attacker.gold += 300
attacker.food += 300
except:
pass
class BarbarianArcher():
def __init__(self, event):
self.hurt = 0
self.shield_count = 0
self.shield_angle = 0
self.gold = 50
self.food = 50
self.attack = 10
self.knockback = 40
self.balloon_speed = 17
self.shoot_cooldown = 0
self.speed = 2
self.health = 100
self.angle = 0
self.event = event
self.surf = pygame.Surface((50, 50))
self.event.barbarians.append(self)
self.rect = self.surf.get_rect(center=(0, 0))
self.x, self.y = self.event.get_coords()
self.surf = pygame.Surface((50, 50))
self.rect = self.surf.get_rect(center=(self.x, self.y))
@property
def innerrect(self):
return self.rect
def explode(self, player, tnt):
self.getHurt(player, 60, t.getAngle(tnt.x, tnt.y, self.x, self.y), 120)
def update(self):
if self.hurt:
self.hurt -= 1
if self.shield_count:
self.shield_count -= 1
if self.shoot_cooldown:
self.shoot_cooldown -= 1
for ob in self.event.server.obs:
if self.rect.colliderect(ob.innerrect):
self.x = self.event.leader.x
self.y = self.event.leader.y
condition = True
while condition:
condition = False
x, y = t.getDir(self.angle, total=self.speed)
self.x += x
self.y += y
self.rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.event.server.obs + self.event.barbarians:
if self.rect.colliderect(ob.innerrect) and ob != self:
condition = True
maxdist = 10000
playerdist = maxdist
player = None
for p in self.event.server.players:
if not p.pending and not p.character.dead:
if t.getDist(self.x, self.y, p.character.x, p.character.y) < maxdist:
maxdist = t.getDist(self.x, self.y, p.character.x, p.character.y)
player = p
playerdist = maxdist
if player == None:
for p in self.event.server.players:
if not p.pending:
p.to_send.append({'action':'draw_barbarian',
'type':'archer',
'hurt':self.hurt,
'coords':(p.character.get_x(self), p.character.get_y(self)),
'angle':self.angle,
'health':self.health,
'shield':(self.shield_angle if self.shield_count else None)})
return
self.angle = t.getAngle(self.x, self.y, player.character.x, player.character.y)
if playerdist < 350:
self.speed = 0
self.shoot()
else:
self.speed = 2
x, y = t.getDir(self.angle, total=self.speed)
self.x += x
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.event.server.obs + self.event.barbarians:
if rect.colliderect(ob.innerrect) and ob != self:
self.x -= x
self.y += y
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.event.server.obs + self.event.barbarians:
if rect.colliderect(ob.innerrect) and ob != self:
self.y -= y
self.rect = self.surf.get_rect(center=(self.x, self.y))
for item in self.event.server.bushes:
if self.rect.colliderect(item.innerrect):
if item.__class__.__name__ == 'SpikyBush':
self.getHurt(self, 4.4, self.angle + 180, 0)
else:
self.getHurt(self, 4, self.angle + 180, 0)
for p in self.event.server.players:
if not p.pending:
if p.character.rect.colliderect(self.rect) and not p.character.dead:
result = p.character.getHurt(10, 'a Barbarian Archer', self.angle, 50, msg='<Victim> ran into <Attacker>. Their gold and food were stolen.')
if p.character.dead and result != 'BAM':
self.gold += p.character.gold
self.food += p.character.food
p.character.gold = 0
p.character.food = 0
for p in self.event.server.players:
if not p.pending:
p.to_send.append({'action':'draw_barbarian',
'type':'archer',
'hurt':self.hurt,
'coords':(p.character.get_x(self), p.character.get_y(self)),
'angle':self.angle,
'health':self.health,
'shield':(self.shield_angle if self.shield_count else None)})
def getHurt(self, attacker, damage, angle, knockback):
if randint(0, 2) == 0 and attacker != self:
self.shield_angle = angle + 180
self.shield_count = 20
for p in self.event.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.rect.size
rect.topleft = (p.character.get_x(self.rect), p.character.get_y(self.rect))
if screen.colliderect(rect):
p.to_send.append({'action':'sound','sound':'bump'})
return ('repelled', self.shield_angle + randint(-20, 20))
else:
x, y = t.getDir(angle, total=(self.speed+knockback))
self.x += x
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.event.server.obs + self.event.barbarians:
if rect.colliderect(ob.innerrect) and ob != self:
self.x -= x
self.y += y
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.event.server.obs + self.event.barbarians:
if rect.colliderect(ob.innerrect) and ob != self:
self.y -= y
self.hurt = 10
self.rect = self.surf.get_rect(center=(self.x, self.y))
self.health -= damage - 4
if self.health <= 0:
self.health = 0
if self in self.event.barbarians:
self.event.barbarians.remove(self)
for p in self.event.server.players:
if not p.pending:
p.message = 'A Barbarian Archer has been defeated!'
p.message_color = (255,205,0)
p.message_count = 160
attacker.gold += self.gold
attacker.food += self.food
def shoot(self):
if not self.shoot_cooldown:
self.shoot_cooldown = 50
Bolt(archer=self)
class BarbarianSwordsman():
def __init__(self, event):
self.hurt = 0
self.angle = 0
self.speed = 5
self.health = 100
self.shield_count = 0
self.shield_angle = 0
self.gold = 50
self.food = 50
self.speed = 2
self.event = event
self.surf = pygame.Surface((50, 50))
self.event.barbarians.append(self)
self.rect = self.surf.get_rect(center=(0, 0))
self.x, self.y = self.event.get_coords()
self.rect = self.surf.get_rect(center=(self.x, self.y))
@property
def innerrect(self):
return self.rect
def explode(self, player, tnt):
self.getHurt(player, 60, t.getAngle(tnt.x, tnt.y, self.x, self.y), 120)
def update(self):
if self.hurt:
self.hurt -= 1
if self.shield_count:
self.shield_count -= 1
for ob in self.event.server.obs:
if self.rect.colliderect(ob.innerrect):
self.x = self.event.leader.x
self.y = self.event.leader.y
condition = True
while condition:
condition = False
x, y = t.getDir(self.angle, total=self.speed)
self.x += x
self.y += y
self.rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.event.server.obs + self.event.barbarians:
if self.rect.colliderect(ob.innerrect) and ob != self:
condition = True
maxdist = 10000
playerdist = maxdist
player = None
for p in self.event.server.players:
if not p.pending and not p.character.dead:
if t.getDist(self.x, self.y, p.character.x, p.character.y) < maxdist:
maxdist = t.getDist(self.x, self.y, p.character.x, p.character.y)
player = p
playerdist = maxdist
if player == None:
for p in self.event.server.players:
if not p.pending:
p.to_send.append({'action':'draw_barbarian',
'type':'swordsman',
'hurt':self.hurt,
'coords':(p.character.get_x(self), p.character.get_y(self)),
'angle':self.angle,
'health':self.health,
'shield':(self.shield_angle if self.shield_count else None)})
return
self.angle = t.getAngle(self.x, self.y, player.character.x, player.character.y)
if playerdist < 350:
self.speed = 5
else:
self.speed = 2
x, y = t.getDir(self.angle, total=self.speed)
self.x += x
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.event.server.obs + self.event.barbarians:
if rect.colliderect(ob.innerrect) and ob != self:
self.x -= x
self.y += y
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.event.server.obs + self.event.barbarians:
if rect.colliderect(ob.innerrect) and ob != self:
self.y -= y
self.rect = self.surf.get_rect(center=(self.x, self.y))
for item in self.event.server.bushes:
if self.rect.colliderect(item.innerrect):
if item.__class__.__name__ == 'SpikyBush':
self.getHurt(self, 4.4, self.angle + 180, 0)
else:
self.getHurt(self, 4, self.angle + 180, 0)
for p in self.event.server.players:
if not p.pending:
if p.character.rect.colliderect(self.rect) and not p.character.dead:
result = p.character.getHurt(10, 'A Barbarian Swordsman', self.angle, 50, msg='<Attacker> killed <Victim> and stole their gold and food.')
if p.character.dead and result != 'BAM':
self.gold += p.character.gold
self.food += p.character.food
p.character.gold = 0
p.character.food = 0
for p in self.event.server.players:
if not p.pending:
p.to_send.append({'action':'draw_barbarian',
'type':'swordsman',
'hurt':self.hurt,
'coords':(p.character.get_x(self), p.character.get_y(self)),
'angle':self.angle,
'health':self.health,
'shield':(self.shield_angle if self.shield_count else None)})
def getHurt(self, attacker, damage, angle, knockback):
if randint(0, 2) == 0 and attacker != self:
self.shield_angle = angle + 180
self.shield_count = 20
for p in self.event.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.rect.size
rect.topleft = (p.character.get_x(self.rect), p.character.get_y(self.rect))
if screen.colliderect(rect):
p.to_send.append({'action':'sound','sound':'bump'})
return ('repelled', self.shield_angle + randint(-20, 20))
else:
x, y = t.getDir(angle, total=(self.speed+knockback))
self.x += x
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.event.server.obs + self.event.barbarians:
if rect.colliderect(ob.innerrect) and ob != self:
self.x -= x
self.y += y
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.event.server.obs + self.event.barbarians:
if rect.colliderect(ob.innerrect) and ob != self:
self.y -= y
self.hurt = 10
self.rect = self.surf.get_rect(center=(self.x, self.y))
self.health -= damage - 4
if self.health <= 0:
self.health = 0
if self in self.event.barbarians:
self.event.barbarians.remove(self)
for p in self.event.server.players:
if not p.pending:
p.message = 'A Barbarian Swordsman has been defeated!'
p.message_color = (255,205,0)
p.message_count = 160
attacker.gold += self.gold
attacker.food += self.food
GameClient.py
import pygame
import pygame as p
from pygame.locals import *
import shelve
import random
import json
import time
import threading
import re
import sys
import os
import __main__
from pymsgbox import alert, confirm, prompt, password
import toolbox as t
from net2web import Client as ParentClient
toolbox = t
answer = ''
with open('../preferences.json', 'r') as fo:
preferences = json.loads(fo.read())
py = preferences.get('py', 'python')
MAP_TEXTURE = preferences.get('map', 'grass')
def get_setting(filepath):
im = p.transform.scale(p.image.load(filepath), (300,300))
walls = p.image.load('../assets/texture building/walls.png')
setting = p.Surface((6000,3900))
width = 6000//300
height = 3900//300
for y in range(height):
for x in range(width):
setting.blit(im, (x*300, y*300))
setting2 = setting.__copy__()
setting2.blit(walls, (0,0))
return setting2, setting
def hack(self):
fo = shelve.open('database/admin')
admin_passwords = fo['passwords']
fo.close()
command = prompt('Enter the command:', title='VillageWars Console')
if command is not None:
attempt = password('You need an admin password to proceed.', title='VillageWars Console')
if attempt in admin_passwords:
self.Send({'action':'hack', 'command':command})
alert('Password Accepted: Command Sent', title='VillageWars Console')
else:
alert('Password Incorrect', title='VillageWars Console')
def find_cursor(cursor_param):
regex = re.compile(r'constant: SYSTEM_CURSOR_(.*)\)>')
res = regex.search(repr(cursor_param))
return res.group(1)
class MyGameClient(ParentClient):
def __init__(self, host, port, screen, clock, username, version, color, skin, xp):
"""
Client constructor function. This is the code that runs once
when a new client is made.
"""
super().__init__(host=host, port=port)
self.color = color
# Start the game
pygame.init()
pygame.mixer.pre_init(buffer=64)
game_width = 1000
game_height = 650
self.started = False
self.screen = screen
self.clock = clock
self.skin = skin
self.xp = xp
self.fps_expected = 30
self.toDraw = []
self.toDrawNext = []
self.disconnected = 0
x, y, width, height = 700, 0, 300, 50
self.dropdown_open = False
self.dropdown_rect = pygame.Rect(x, y, width, height)
self.gamemodes = ['Classic', 'Express', 'Immediate', 'OP']
self.gamemode = 'Classic'
self.back_pic = p.image.load('../assets/BG_SciFi.png')
self.ocean_pics = [p.transform.scale(p.image.load('../assets/ocean/' + i), (1000, 1000)) for i in os.listdir('../assets/ocean/')]
self.ocean_frame = 0
self.players = [(p.transform.scale(p.image.load('../assets/Skins/%s.png' % (i)), (50, 50)), p.transform.scale(p.image.load('../assets/Skins/%sh.png' % (i)), (50, 50))) for i in range(len(os.listdir('../assets/Skins'))//2)]
self.archer = p.transform.scale(p.image.load('../assets/Enemy_04.png'), (50, 50))
self.bolt = p.image.load('../assets/barbarians/bolt.png')
self.startgame_icon = p.image.load('../assets/Startgame_btn.png')
self.startgame_icon_over = p.image.load('../assets/Startgame_btn_over.png')
self.startgame_icon_locked = p.image.load('../assets/Startgame_btn_locked.png')
self.balloon = p.image.load('../assets/balloon.png')
self.op_balloon = p.image.load('../assets/balloon2.png')
self.speedy_plus_op = p.image.load('../assets/Drop.png')
self.speedy_balloon = p.image.load('../assets/DropSmall.png')
self.robot = p.transform.scale(p.image.load('../assets/Enemy_05.png'), (50, 50))
self.robot_hurt = p.transform.scale(p.image.load('../assets/Enemy_05_hurt.png'), (50, 50))
self.animations = {
'Splash':(p.image.load('../assets/splash1.png'), p.image.load('../assets/splash2.png'), p.image.load('../assets/splash3.png')),
'Explosion':(p.image.load('../assets/explode1.png'), p.image.load('../assets/explode2.png'), p.image.load('../assets/explode3.png')),
'BAM':(p.transform.scale(p.image.load('../assets/LargeExplosion1.png'), (360, 360)), p.transform.scale(p.image.load('../assets/LargeExplosion1.png'), (360, 360)), p.transform.scale(p.image.load('../assets/LargeExplosion2.png'), (360, 360)), p.transform.scale(p.image.load('../assets/LargeExplosion2.png'), (360, 360)), p.transform.scale(p.image.load('../assets/LargeExplosion3.png'), (360, 360)), p.transform.scale(p.image.load('../assets/LargeExplosion3.png'), (360, 360)))
}
self.red = p.image.load('../assets/buildings/red.png')
self.blue = p.image.load('../assets/buildings/blue.png')
self.green = p.image.load('../assets/buildings/green.png')
self.yellow = p.image.load('../assets/buildings/yellow.png')
self.black = p.image.load('../assets/buildings/black.png')
self.preview = p.image.load('../assets/buildings/preview.png')
self.house = p.image.load('../assets/buildings/House.png')
self.house_burnt = p.image.load('../assets/buildings/House_burnt.png')
self.building_person = p.transform.scale(p.image.load('../assets/Skins/4.png'), (50, 50))
self.miner = p.transform.scale(p.image.load('../assets/Skins/2.png'), (50, 50))
self.farmer = p.transform.scale(p.image.load('../assets/Skins/4.png'), (50, 50))
self.barbarians = {
'leader':[p.image.load('../assets/barbarians/leader.png'), p.image.load('../assets/barbarians/leaderh.png'), p.image.load('../assets/barbarians/leaderm.png')],
'archer':[p.image.load('../assets/barbarians/archer.png'), p.image.load('../assets/barbarians/archerh.png')],
'swordsman':[p.image.load('../assets/barbarians/swordsman.png'), p.image.load('../assets/barbarians/swordsmanh.png')]
}
self.barbarian_range = p.transform.scale(p.image.load('../assets/barbarians/range.png'), (700, 700))
self.shield = p.image.load('../assets/barbarians/shield.png')
self.barbarian_banner = p.transform.scale(p.image.load('../assets/barbarians/banner.png'), (45, 90))
for i, b in enumerate(self.barbarians['leader']):
self.barbarians['leader'][i] = p.transform.scale(b, (50, 50))
for i, b in enumerate(self.barbarians['archer']):
self.barbarians['archer'][i] = p.transform.scale(b, (50, 50))
for i, b in enumerate(self.barbarians['swordsman']):
self.barbarians['swordsman'][i] = p.transform.scale(b, (50, 50))
self.startgame_rect = self.startgame_icon.get_rect(topleft=(445, 400))
self.Setting, self.no_walls_setting = get_setting('../assets/texture building/%s.png' % (MAP_TEXTURE))
self.food_image = p.image.load('../assets/food.png')
self.food_used = p.image.load('../assets/food_used.png')
self.food_mine = p.image.load('../assets/food_mine.png')
self.plate = p.transform.scale(p.image.load('../assets/meals/plate.png'), (100, 100))
self.meals = [
p.transform.scale(p.image.load('../assets/meals/meal1.png'), (100, 100)),
p.transform.scale(p.image.load('../assets/meals/meal2.png'), (100, 100)),
p.transform.scale(p.image.load('../assets/meals/meal3.png'), (100, 100)),
p.transform.scale(p.image.load('../assets/meals/meal4.png'), (100, 100)),
]
self.meals = [p.transform.scale(p.image.load('../assets/meals/meal%s.png' % (num - 1)), (100, 100)) for num in range(len(os.listdir('../assets/meals'))) if num not in (0, 1)]
self.gold_image = p.transform.scale(p.image.load('../assets/gold.png'), (45, 45))
self.gold_mine = p.transform.scale(p.image.load('../assets/gold_mine.png'), (45, 45))
self.mine = p.image.load('../assets/mine.png')
self.x = p.image.load('../assets/x.png')
self.x_hov = p.image.load('../assets/x_hov.png')
self.tree = p.transform.scale(p.image.load('../assets/trees/tree1.png'), (200, 280))
self.sappling = p.image.load('../assets/trees/sappling.png')
self.large_font = p.font.SysFont('default', 80)
self.medium_font = p.font.SysFont('default', 40)
self.small_font = p.font.SysFont('default', 20)
self.crate = p.transform.scale(p.image.load('../assets/crate.png'), (50, 50))
self.barrel = p.transform.scale(p.image.load('../assets/Barrel.png'), (50, 50))
self.barrel_tnt = p.transform.scale(p.image.load('../assets/BarrelTNT.png'), (50, 50))
self.barrel_broken = p.transform.scale(p.image.load('../assets/BarrelRubble.png'), (50, 50))
self.tnt = p.transform.scale(p.image.load('../assets/TNT.png'), (50, 50))
self.gate = p.image.load('../assets/gate.png')
self.spiky_bush = p.image.load('../assets/spiky_bush.png')
self.ready = False
self.ready_text = self.small_font.render('READY', True, (0,255,0))
self.not_ready_text = self.small_font.render('NOT READY', True, (255,0,0))
self.host_text = self.small_font.render('host', True, (255,0,0))
self.escape_count = 0
self.username = username
p.mixer.init()
self.sound_be = pygame.mixer.Sound('../assets/sfx/explosion-big.wav') # be for big explosion
self.sound_se = pygame.mixer.Sound('../assets/sfx/explosion-small.wav') # se for small explosion
self.sound_sp = pygame.mixer.Sound('../assets/sfx/splash.wav') # sp for splash
self.sound_sh = pygame.mixer.Sound('../assets/sfx/splash-heavy.wav') # sh for splash heavy
self.sound_shot = pygame.mixer.Sound('../assets/sfx/shot.wav')
self.sound_bump = pygame.mixer.Sound('../assets/sfx/bump.wav')
self.sound_ba = pygame.mixer.Sound('../assets/sfx/break.wav') # ba for barrel
self.sound_bb = pygame.mixer.Sound('../assets/sfx/building.wav') # bb for broken building
self.sound_ow = pygame.mixer.Sound('../assets/sfx/open_window.wav')
self.sound_cw = pygame.mixer.Sound('../assets/sfx/close_window.wav')
self.musics = {
'steppingpebbles':'../assets/sfx/stepPebblesLoop.mp3',
'village':'../assets/sfx/villageLoop.mp3',
'barbarianraid':'../assets/sfx/War song.mp3'
}
self.paused = False
self.F3 = False
with open('tips.json', 'r') as tipfile:
tips = json.loads(tipfile.read())
self.tips = tips['basic_tips']
num_rare = random.choice([0,0,0,0,1,1,1,2,2,3])
random.shuffle(tips['rare_tips'])
for i, rare_tip in enumerate(tips['rare_tips'][:]):
tips['rare_tips'][i] = '+' + rare_tip
self.tips.extend(tips['rare_tips'][:num_rare])
self.tip_frame = 0
self.tip = 0
self.achievement_pic = p.transform.scale(p.image.load('../assets/achievement.png'), (225, 50))
self.achievement = [0, 'None']
self.version = version
def update(self):
"""
Client update function. This is the function that runs over and
over again, once every frame of the game.
"""
self.mouseX, self.mouseY = p.mouse.get_pos()[:2]
self._connected = False
self.Pump()
global running
if answer == 'OK':
p.quit()
exit()
global cursor
old_cursor = p.mouse.get_cursor()
if not find_cursor(cursor) == find_cursor(old_cursor):
p.mouse.set_cursor(cursor)
cursor = p.cursors.Cursor(pygame.SYSTEM_CURSOR_ARROW)
if self.achievement[0]:
self.achievement[0] -= 1
if self.achievement[0] >= 90:
x = (225/30) * (120-self.achievement[0])
elif self.achievement[0] <= 30:
x = (225/30) * self.achievement[0]
else:
x = 225
self.toDraw.append((self.achievement_pic, (1000-x, 55)))
text = self.small_font.render(self.achievement[1], True, (0,0,0))
text_rect = text.get_rect(midtop = (1120-x, 85))
self.toDraw.append([text, text_rect])
if not self._connected:
self.disconnected += 1
else:
self.disconnected = 0
if self.escape_count:
self.escape_count -= 1
if self.disconnected == 50 and self.connected:
c = confirm('Connection is low.', title='VillageWars', buttons=['Quit', 'Continue'])
if c == 'Quit':
p.quit()
sys.exit()
#p.mixer.music.stop()
#self.screen.blit(p.image.load('../assets/Disconnected.png'), (0, 0))
#pygame.display.flip()
#while True:
# for e in p.event.get():
# if e.type == QUIT:
# p.quit()
# sys.exit()
#
# fps = self.clock.get_fps()
# self.clock.tick(30)
# pygame.display.set_caption("VillageWars fps: " + str(fps))
self.tip_frame += 1
if self.tip_frame == 250:
self.tip_frame = 0
self.tip += 1
if self.tip == len(self.tips):
self.tip = 0
random.shuffle(self.tips)
if 'Always get a Miner\'s Guild and a Farmer\'s Guild first!' in self.tips:
self.tips.remove('Always get a Miner\'s Guild and a Farmer\'s Guild first!')
# Set running to False if the player clicks the X
global music_playing
for event in pygame.event.get():
if event.type == QUIT:
def confirm_exit():
global answer
answer = confirm('The game is still going. Are you sure you want to quit?')
thread = threading.Thread(target=confirm_exit)
thread.start()
if event.type == KEYUP and event.key == K_F1 and self.started:
music_playing = not music_playing
if music_playing:
p.mixer.music.pause()
else:
p.mixer.music.play(-1, 0.0)
if event.type == KEYUP and event.key == K_F2:
num = len(os.listdir('../run/screenshots')) + 1
name = 'sreenshot' + str(num)
p.image.save(self.screen, '../run/screenshots/%s.png' % (name))
alert('Screenshot saved as %s.png' % (name))
if event.type == KEYUP and event.key == K_F6:
self.Send({'action':'F6'})
if event.type == KEYUP and event.key == K_F10:
hack(self)
if event.type == KEYUP and event.key == K_F3:
self.F3 = not self.F3
if event.type == KEYUP and event.key == K_F8:
self.Send({'action':'startgame'}) # Cheaty way to start the server before everyone's ready
#if event.type == KEYUP and event.key == K_ESCAPE: # Removed because this is BAD!
# if not self.escape_count:
# self.Send({'action':'pause'})
# self.escape_count = 30
if event.type == MOUSEMOTION:
self.mouseX = event.pos[0]
self.mouseY = event.pos[1]
if event.type == MOUSEBUTTONUP:
if self.dropdown_rect.collidepoint(event.pos):
self.dropdown_open = not self.dropdown_open
else:
self.dropdown_open = False
_keys = p.key.get_pressed()
keys = []
for i in range(len(list(_keys))):
keys.append(_keys[i])
mouse = list(p.mouse.get_pos())
mouse_click = p.mouse.get_pressed()
mouse.append(mouse_click[0])
mouse.append(mouse_click[1])
mouse.append(mouse_click[2])
self.Send({'action': 'keys', 'keys': keys, 'mouse':mouse})
_screen = p.Surface((1000, 650))
for image in self.toDraw:
_screen.blit(image[0], image[1])
if self.paused:
_screen.blit(self.paused_image, (0, 0))
self.screen.blit(_screen, (0, 0))
# Tell pygame to update the screen
pygame.display.flip()
fps = self.clock.get_fps()
self.Send({'action':'fps', 'fps':fps})
self.clock.tick(self.fps_expected)
pygame.display.set_caption("VillageWars " + self.version + " fps: " + str(fps))
def ShutDown(self):
"""
Client ShutDown function. Disconnects and closes the game.
"""
self.connected = False
sys.exit()
#####################################
### Client-side Network functions ###
#####################################
"""
Each one of these "Network_" functions defines a command
that the server will tell you (the client) to do.
"""
def Network_hack_fail(self, data):
print('Exception:', data['msg'])
def Network_gamemode(self, data):
self.gamemode = data['gamemode']
def Network_receive(self, data):
#print(time.time() - data['timestamp'])
self.diconnected = 0
self._connected = True
if True: #time.time() - data['timestamp'] < 0.5:
self.fps_expected = 30
for i in data['data']:
exec('self.Network_' + i['action'] + '(' + repr(i) + ')')
else:
self.fps_expected = 60
def Network_fall(self, data):
self.Setting = self.no_walls_setting
p.mixer.music.stop()
p.mixer.music.load('../assets/sfx/villageLoop.mp3')
global music_playing
if music_playing:
p.mixer.music.play(-1, 0.0)
def Network_achievement(self, data):
self.achievement = [120, data['type']]
def Network_pause(self, data):
self.paused = not self.paused
def Network_flip(self, data):
if not self.paused:
self.toDraw.clear()
self.toDraw = self.toDrawNext[:]
self.toDrawNext.clear()
def Network_draw_setting(self, data):
self.toDrawNext.append([self.Setting, data['coords']])
def Network_draw_lobby_background(self, data):
self.toDrawNext.append([self.Setting, data['coords']])
image = self.crate
for i in range(1000//50):
rect = image.get_rect(center=(data['x'] + i*50, data['y']))
self.toDrawNext.append([image, rect])
for i in range(1000//50):
rect = image.get_rect(center=(data['x'] + i*50, data['y'] + 650))
self.toDrawNext.append([image, rect])
for i in range(700//50):
rect = image.get_rect(center=(data['x'], data['y'] + i*50))
self.toDrawNext.append([image, rect])
for i in range(700//50):
rect = image.get_rect(center=(data['x'] + 1000, data['y'] + i*50))
self.toDrawNext.append([image, rect])
image = p.Surface((500, 100), SRCALPHA)
rect = image.get_rect(center=(data['x']+500, data['y']+500))
if rect.collidepoint((500,325)):
image.fill((200,200,250,128))
if not self.ready:
self.ready = not self.ready
self.Send({'action':'ready', 'ready':self.ready})
else:
image.fill((0,0,200,128))
if self.ready:
self.ready = not self.ready
self.Send({'action':'ready', 'ready':self.ready})
self.toDrawNext.append([image, rect])
def Network_draw_background(self, data):
self.toDrawNext.append([self.ocean_pics[self.ocean_frame], (0, 0)])
self.ocean_frame += 1
self.ocean_frame %= 40
def Network_preview(self, data):
if not data['ArcheryTower?']:
image = self.house
rect = image.get_rect(center=(500, 185))
cage = self.preview
cage = p.transform.scale(cage, data['dimensions'])
cage_rect = cage.get_rect(midtop=rect.midtop)
self.toDrawNext.append([cage, cage_rect])
else:
cage = p.transform.scale(self.preview, (360, 360))
cage_rect = cage.get_rect(center=(500, 85))
self.toDrawNext.append([cage, cage_rect])
def Network_draw_avatar(self, data):
avatar_pic = self.players[data['skin']][0]
avatar_rect = avatar_pic.get_rect(center=data['coords'])
avatar_pic, avatar_rect = t.rotate(avatar_pic, avatar_rect, data.get('angle', 0))
self.toDrawNext.append([avatar_pic, avatar_rect])
text = self.medium_font.render(data['username'], True, data['color'])
text_rect = text.get_rect(midbottom = avatar_rect.midtop)
text_rect.y -= 4
self.toDrawNext.append([text, text_rect])
#if data['host']:
#mouse = p.mouse.get_pos()
#click = p.mouse.get_pressed()
#image = self.x
#rect = image.get_rect(center=avatar_rect.topright)
#if rect.collidepoint(mouse):
# global cursor
# cursor = p.cursors.Cursor(pygame.SYSTEM_CURSOR_HAND)
# image = self.x_hov
# if click[0]:
# self.Send({'action':'hack', 'command':'kick(self, "%s")' % (data['username'])})
#self.toDrawNext.append((image, rect))
def Network_victory(self, data):
p.mixer.music.stop()
victory = p.mixer.Sound('../assets/sfx/victory.mp3')
victory.play()
def Network_animation(self, data):
image = self.animations[data['name']][data['frame']]
rect = image.get_rect(center=data['coords'])
self.toDrawNext.append((image, rect))
def Network_congrats(self, data):
screen = p.Surface((1000, 650))
screen.fill((255,255,0))
self.toDrawNext.append([screen, (0, 0)])
if data['color'] == (255,255,0): data['color'] = (0,0,0)
name = self.large_font.render('You won the game!', True, data['color'])
text_rect = name.get_rect(midtop=(500, 30))
self.toDrawNext.append([name, text_rect])
name = self.medium_font.render('Kills: ' + str(data['kills']), True, (0,0,0))
text_rect = name.get_rect(topleft=(400, 200))
self.toDrawNext.append([name, text_rect])
name = self.medium_font.render('Eliminations: ' + str(data['eliminations']), True, (0,0,0))
text_rect = name.get_rect(topleft=(400, 320))
self.toDrawNext.append([name, text_rect])
name = self.medium_font.render('Buildings Destroyed: ' + str(data['destroyed']), True, (0,0,0))
text_rect = name.get_rect(topleft=(400, 440))
self.toDrawNext.append([name, text_rect])
name = self.medium_font.render('Deaths: ' + str(data['deaths']), True, (255,0,0))
text_rect = name.get_rect(topleft=(400, 560))
self.toDrawNext.append([name, text_rect])
keys = p.key.get_pressed()
if keys[K_ESCAPE]:
global running
running = False
def Network_end(self, data):
p.mixer.music.stop()
screen = p.Surface((1000, 650))
screen.fill((128, 128, 128))
self.toDrawNext.append([screen, (0, 0)])
name = self.large_font.render(data['winner'] + ' won the game.', True, (0,0,0))
text_rect = name.get_rect(midtop=(500, 30))
self.toDrawNext.append([name, text_rect])
name = self.medium_font.render('Kills: ' + str(data['kills']), True, (0,0,0))
text_rect = name.get_rect(topleft=(400, 200))
self.toDrawNext.append([name, text_rect])
name = self.medium_font.render('Eliminations: ' + str(data['eliminations']), True, (0,0,0))
text_rect = name.get_rect(topleft=(400, 320))
self.toDrawNext.append([name, text_rect])
name = self.medium_font.render('Buildings Destroyed: ' + str(data['destroyed']), True, (0,0,0))
text_rect = name.get_rect(topleft=(400, 440))
self.toDrawNext.append([name, text_rect])
name = self.medium_font.render('Deaths: ' + str(data['deaths']), True, (255,0,0))
text_rect = name.get_rect(topleft=(400, 560))
self.toDrawNext.append([name, text_rect])
def Network_ingame(self, data):
self.toDrawNext.append([self.Setting, data['coords']])
def Network_music_change(self, data):
p.mixer.music.stop()
p.mixer.music.load(self.musics[data['music']])
global music_playing
if music_playing:
p.mixer.music.play(-1, 0.0)
def Network_draw_barbarian(self, data):
if self.F3:
image = self.barbarian_range
rect = image.get_rect(center=data['coords'])
self.toDrawNext.insert(6, (image, rect))
image = self.barbarians[data['type']][bool(data['hurt'])]
rect = image.get_rect(center=data['coords'])
image, rect = t.rotate(image, rect, data['angle'])
if data['type'] == 'leader':
banner = self.barbarian_banner
banner_rect = banner.get_rect(bottomleft=rect.center)
self.toDrawNext.append((banner, banner_rect))
self.toDrawNext.append((image, rect))
username_text = self.small_font.render('Barbarian ' + data['type'].title(), True, (0,0,0))
text_rect = username_text.get_rect(midbottom = (rect.midtop[0], rect.midtop[1] - 15))
self.toDrawNext.append([username_text, text_rect])
if data['shield'] != None:
image = self.shield
rect = image.get_rect(center=data['coords'])
image, rect = t.rotate(image, rect, data['shield'])
self.toDrawNext.append((image, rect))
health_bar = p.Surface((50, 10))
health_bar.fill((255, 0, 0))
health_rect = health_bar.get_rect(midbottom=rect.midtop)
green_bar = p.Surface((int(data['health']/2), 10))
green_bar.fill((0,255,0))
health_bar.blit(green_bar, (0, 0))
self.toDrawNext.append([health_bar, health_rect])
def Network_hud(self, data):
gold = self.medium_font.render('Gold: ' + str(data['gold']), True, (255,205,0))
gold_rect = gold.get_rect(topright = (950,260))
self.toDrawNext.append([gold, gold_rect])
food = self.medium_font.render('Food: ' + str(data['food']), True, (5,255,5))
food_rect = food.get_rect(topright = (950,300))
self.toDrawNext.append([food, food_rect])
if self.F3:
x = round(data['x'])
y = round(data['y'])
coords = self.medium_font.render('x=' + str(x) + ', y=' + str(y), True, (0,0,0))
coords_rect = coords.get_rect(topleft = (50,100))
self.toDrawNext.append([coords, coords_rect])
if x > 3000:
if y > 1950:
q = 'Bottom-right'
else:
q = 'Top-right'
else:
if y > 1950:
q = 'Bottom-left'
else:
q = 'Top-left'
coords = self.medium_font.render('Quadrant: ' + q, True, (0,0,0))
coords_rect = coords.get_rect(topleft = (50,130))
self.toDrawNext.append([coords, coords_rect])
if -45 <= data['angle'] <= 45:
d = 'East (towards positive x)'
elif 45 <= data['angle'] <= 135:
d = 'North (towards negative y)'
elif -135 <= data['angle'] <= -45:
d = 'South (towards positive y)'
elif -135 >= data['angle'] or data['angle'] >= 135:
d = 'West (towards negative x)'
text = self.medium_font.render('Facing: ' + d, True, (0,0,0))
text_rect = text.get_rect(topleft = (50,160))
self.toDrawNext.append([text, text_rect])
gametime = data.get('gametime')
if gametime:
gametime = round(gametime)
seconds = gametime % 60 + 1
minutes = gametime // 60
#print(seconds, minutes)
if seconds == 60:
seconds = 0
minutes += 1
if minutes > 0 and seconds > 9:
gametime = str(minutes) + ':' + str(seconds)
elif seconds > 9:
gametime = str(seconds)
else:
if minutes > 0:
gametime = str(minutes) + ':' + '0' + str(seconds)
else:
gametime = str(seconds)
text = self.medium_font.render('Game Time: ' + gametime, True, (0,0,0))
text_rect = text.get_rect(topleft = (50,190))
self.toDrawNext.append([text, text_rect])
fps = self.clock.get_fps()
text = self.medium_font.render('FPS: ' + str(fps), True, (0,0,0))
text_rect = text.get_rect(topleft = (50,220))
self.toDrawNext.append([text, text_rect])
if data['food?']:
image = self.meals[data['type']]
else:
image = self.plate
mouse = p.mouse.get_pos()
rect = image.get_rect(center=(890, 130))
if rect.collidepoint(mouse) and image != self.plate:
image = p.transform.scale(image, (110, 110))
rect = image.get_rect(center=(890, 130))
pressed = p.mouse.get_pressed()
if pressed[0]:
self.Send({'action':'eat'})
self.toDrawNext.append([image, rect])
if data['crates'] > 0:
text = self.medium_font.render('x ' + str(data['crates']), True, (0,0,0))
text_rect = text.get_rect(midleft=(940, 20))
self.toDrawNext.append([text, text_rect])
self.toDrawNext.append([p.transform.scale(self.crate, (30, 30)), (900, 5)])
if data['spiky_bushes'] > 0:
text = self.medium_font.render('x ' + str(data['spiky_bushes']), True, (0,0,0))
text_rect = text.get_rect(midleft=(940, 75))
self.toDrawNext.append([text, text_rect])
self.toDrawNext.append([p.transform.scale(self.spiky_bush, (30, 30)), (900, 60)])
def Network_draw_player(self, data):
global cursor
cursor = p.cursors.Cursor(pygame.SYSTEM_CURSOR_CROSSHAIR)
if data.get('in_barrel', (0,False))[1]:
if data['in_barrel'][0] == True:
image = self.players[data['skin']][data['hurt']]
rect = image.get_rect(center=(data['coords']))
image, rect = t.rotate(image, rect, data['angle'])
self.toDrawNext.append([image, rect])
image = self.barrel_broken
elif data['in_barrel'][0] == False:
image = self.barrel
else:
image = self.barrel_tnt
rect = image.get_rect(center=(data['coords']))
else:
image = self.players[data['skin']][data['hurt']]
rect = image.get_rect(center=(data['coords']))
image, rect = t.rotate(image, rect, data['angle'])
self.toDrawNext.append([image, rect])
username_text = self.small_font.render(data['username'], True, data['color'])
text_rect = username_text.get_rect(midbottom = (rect.midtop[0], rect.midtop[1] - 15))
if not data.get('in_barrel', False)[1]:
self.toDrawNext.append([username_text, text_rect])
health_bar = p.Surface((int(data['max_health'] / 2), 10))
health_bar.fill((255, 0, 0))
health_rect = health_bar.get_rect(midbottom=rect.midtop)
green_bar = p.Surface((int(data['health']/2), 10))
green_bar.fill((0,255,0))
health_bar.blit(green_bar, (0, 0))
self.toDrawNext.append([health_bar, health_rect])
if data['shield'] != None:
image = self.shield
rect = image.get_rect(center=data['coords'])
image, rect = t.rotate(image, rect, data['shield'])
self.toDrawNext.append((image, rect))
if self.F3:
health = self.small_font.render(str(data['health']) + '/' + str(data['max_health']), True, (240,240,240))
text_rect = health.get_rect(midbottom = (text_rect.midtop[0], text_rect.midtop[1] - 4))
self.toDrawNext.append([health, text_rect])
def Network_draw_NPC(self, data):
if data['image'] == 'farmer':
image = self.farmer
name = 'Farmer'
elif data['image'] == 'miner':
image = self.miner
name = 'Miner'
rect = image.get_rect(topleft=(data['coords']))
image, rect = t.rotate(image, rect, data['angle'])
self.toDrawNext.append([image, rect])
username_text = self.small_font.render(name, True, data['color'])
text_rect = username_text.get_rect(midbottom = (rect.midtop[0], rect.midtop[1] - 15))
self.toDrawNext.append([username_text, text_rect])
status_text = self.small_font.render(data['status'], True, (0,0,0))
text_rect = status_text.get_rect(midbottom = (rect.midtop[0], rect.midtop[1] + 5))
self.toDrawNext.append([status_text, text_rect])
def Network_draw_InnPC(self, data):
image = self.players[0][0]
rect = image.get_rect(center=(data['coords']))
image, rect = t.rotate(image, rect, data['angle'])
self.toDrawNext.append([image, rect])
username_text = self.small_font.render(data['type'], True, data['color'])
text_rect = username_text.get_rect(midbottom = (rect.midtop[0], rect.midtop[1] - 15))
self.toDrawNext.append([username_text, text_rect])
health_bar = p.Surface((50, 10))
health_bar.fill((255,0,0))
health_rect = health_bar.get_rect(midbottom=rect.midtop)
green_bar = p.Surface((round(data['health'] / 2), 10))
green_bar.fill((0,255,0))
health_bar.blit(green_bar, (0, 0))
self.toDrawNext.append([health_bar, health_rect])
def Network_draw_robot(self, data):
if data['image'] == 'regular':
image = self.robot
elif data['image'] == 'hurt':
image = self.robot_hurt
rect = image.get_rect(center=(data['coords']))
image, rect = t.rotate(image, rect, data['angle'])
self.toDrawNext.append([image, rect])
username_text = self.small_font.render(data['name'], True, data['color'])
text_rect = username_text.get_rect(midbottom = (rect.midtop[0], rect.midtop[1] - 15))
self.toDrawNext.append([username_text, text_rect])
health_bar = p.Surface((50, 10))
health_bar.fill((255,0,0))
health_rect = health_bar.get_rect(midbottom=rect.midtop)
green_bar = p.Surface((round(data['health'] / 2), 10))
green_bar.fill((0,255,0))
health_bar.blit(green_bar, (0, 0))
self.toDrawNext.append([health_bar, health_rect])
def Network_draw_farm(self, data):
if data['state'] == 'good':
image = self.food_image
elif data['state'] == 'mine':
image = self.food_mine
else:
image = self.food_used
self.toDrawNext.append([image, data['coords']])
def Network_draw_gold(self, data):
image = None
if data['state'] == 'good':
image = self.gold_image
elif data['state'] == 'mine':
image = self.gold_mine
if image != None:
self.toDrawNext.append([image, data['coords']])
def Network_draw_mine(self, data):
image = self.mine
if data['right'] == True:
image = p.transform.flip(image, True, False)
self.toDrawNext.append([image, data['coords']])
def Network_draw_balloon(self, data):
balloon_type = data.get('type', 'default')
image = self.balloon
if balloon_type == 'bolt':
image = self.bolt
if balloon_type == 'op':
image = self.op_balloon
if balloon_type == 'speedy':
image = self.speedy_balloon
if balloon_type == 'speedy+op':
image = self.speedy_plus_op
rect = image.get_rect(center=(data['coords']))
image, rect = t.rotate(image, rect, data['angle'])
self.toDrawNext.append([image, rect])
def Network_draw_building(self, data):
if data['image'] == 'house':
if data['state'] == 'alive':
image = self.house
else:
image = self.house_burnt
rect = image.get_rect(center=data['coords'])
color = tuple(data['color'])
if color == (255,0,0):
cage = self.red
elif color == (0,255,0):
cage = self.green
elif color == (0,0,255):
cage = self.blue
elif color == (255,255,0):
cage = self.yellow
elif color == (0,0,0):
cage = self.black
cage = p.transform.scale(cage, data['dimensions'])
cage_rect = cage.get_rect(midtop=rect.midtop)
self.toDrawNext.append([cage, cage_rect])
self.toDrawNext.append([image, rect])
if data['state'] == 'alive':
person = self.building_person
person_rect = image.get_rect(midtop=(rect.midbottom[0], rect.midbottom[1] + 50))
person, person_rect = t.rotate(person, person_rect, data['angle'])
self.toDrawNext.append([person, person_rect])
name = self.small_font.render(data['type'], True, data['color'])
text_rect = name.get_rect(midbottom = (person_rect.midtop[0], person_rect.midtop[1] - 30))
self.toDrawNext.append([name, text_rect])
name = self.small_font.render('(Level ' + str(data['level']) + ')', True, data['color'])
text_rect = name.get_rect(midbottom = (person_rect.midtop[0], person_rect.midtop[1] - 15))
self.toDrawNext.append([name, text_rect])
health_bar = p.Surface((int(data['max_health'] / 2), 10))
health_bar.fill((255, 0, 0))
health_rect = health_bar.get_rect(midbottom=person_rect.midtop)
green_bar = p.Surface((int(data['health']/2), 10))
green_bar.fill((0,255,0))
health_bar.blit(green_bar, (0, 0))
self.toDrawNext.append([health_bar, health_rect])
def Network_archery_tower(self, data):
color = tuple(data['color'])
if color == (255,0,0):
cage = self.red
elif color == (0,255,0):
cage = self.green
elif color == (0,0,255):
cage = self.blue
elif color == (255,255,0):
cage = self.yellow
elif color == (0,0,0):
cage = self.black
cage = p.transform.scale(cage, (360, 360))
cage_rect = cage.get_rect(center=data['coords'])
self.toDrawNext.append([cage, cage_rect])
person = self.archer
person_rect = person.get_rect(midtop=(data['coords']))
person, person_rect = t.rotate(person, person_rect, data['angle'])
if data['state'] == 'alive':
self.toDrawNext.append([person, person_rect])
if data['state'] == 'alive':
name = self.small_font.render('Archery Tower', True, data['color'])
else:
name = self.small_font.render('Archery Tower (Broken)', True, data['color'])
text_rect = name.get_rect(midbottom = (person_rect.midtop[0], person_rect.midtop[1] - 15))
self.toDrawNext.append([name, text_rect])
if data['state'] == 'alive':
health_bar = p.Surface((150, 10))
health_rect = health_bar.get_rect(midbottom=person_rect.midtop)
health_bar.fill((255,0,0))
green_bar = p.Surface((int(data['health']/2), 10))
green_bar.fill((0,255,0))
health_bar.blit(green_bar, (0, 0))
self.toDrawNext.append([health_bar, health_rect])
def Network_sound(self, data):
if data['sound'] == 'TNT':
self.sound_be.play()
if data['sound'] == 'shot':
self.sound_shot.play()
if data['sound'] == 'die':
self.sound_se.play()
if data['sound'] == 'splash':
self.sound_sp.play()
if data['sound'] == 'opsplash':
self.sound_sh.play()
if data['sound'] == 'bump':
self.sound_bump.play()
if data['sound'] == 'building':
self.sound_bb.play()
if data['sound'] == 'ow':
self.sound_ow.play()
if data['sound'] == 'cw':
self.sound_cw.play()
if data['sound'] == 'barrel':
self.sound_ba.play()
def Network_num_buildings(self, data):
y = 500
x = 990
for user in data['users']:
username = self.small_font.render(user['name'] + ' has ' + str(user['bs']) + ' buildings.', True, user['color'])
text_rect = username.get_rect(topright=(x, y+user['num']*30))
self.toDrawNext.append([username, text_rect])
def Network_chat(self, data):
y = 20
for message in reversed(data['messages']):
color = list(message['color'])
#color.append(message['fade'])
m = self.medium_font.render(message['message'], True, color)
m.set_alpha(message['fade'])
text_rect = m.get_rect(topleft=(20, y))
self.toDrawNext.append([m, text_rect])
y += 30
def Network_startgame(self, data):
p.mixer.music.stop()
p.mixer.music.load('../assets/sfx/stepPebblesLoop.mp3')
self.started = True
global music_playing
if music_playing:
p.mixer.music.play(-1, 0.00)
def Network_text(self, data):
if data['text']:
name = self.medium_font.render(data['text'], True, (0,0,255))
else:
if self.tips[self.tip].startswith('+'):
name = self.medium_font.render('TIP: ' + self.tips[self.tip][1:], True, (255,0,128))
else:
name = self.medium_font.render('TIP: ' + self.tips[self.tip], True, (255,205,0))
text_rect = name.get_rect(midbottom=(500, 500))
self.toDrawNext.append([name, text_rect])
def Network_time(self, data):
text = self.medium_font.render(data['time'], True, (0,0,0))
text_rect = text.get_rect(midbottom=(500, 640))
self.toDrawNext.append([text, text_rect])
def Network_draw_obstacle(self, data):
if data['image'] == 'tree':
image = self.tree
if data['image'] == 'sappling':
image = self.sappling
if data['image'] == 'crate':
image = self.crate
if data['image'] == 'vine':
image = self.vine
if data['image'] == 'gate':
if data['rotated?']:
image = p.transform.rotate(self.gate, 90)
else:
image = self.gate
if data['image'] == 'spiky bush':
image = self.spiky_bush
if data['image'] == 'TNT':
image = self.tnt
if data['image'] == 'barrel':
image = self.barrel_broken if data['max_health'] / (1+data['health']) > 2 else self.barrel
if data.get('explosive', False):
image = self.barrel_tnt
rect = image.get_rect(center=data['coords'])
image, rect = t.rotate(image, rect, data.get('angle', 0))
self.toDrawNext.append([image, rect])
if data['image'] != 'barrel' and data['image'] != 'crate' and data['image'] != 'gate' and data['image'] != 'TNT' and data['image'] != 'spiky bush' and data['image'] != 'vine':
health_bar = p.Surface((int(data['max_health']/2), 12))
health_bar.fill((255, 0, 0))
health_rect = health_bar.get_rect(midbottom=rect.midtop)
green_bar = p.Surface((int(data['health']/2), 12))
green_bar.fill((0,255,0))
health_bar.blit(green_bar, (0, 0))
self.toDrawNext.append([health_bar, health_rect])
def Network_draw_window(self, data):
grey = p.Surface((610, 618))
large_rect = grey.get_rect(topleft=(195, 4))
grey.fill((128,128,128))
self.toDrawNext.append([grey, large_rect])
if large_rect.collidepoint(p.mouse.get_pos()):
global cursor
cursor = p.cursors.Cursor(pygame.SYSTEM_CURSOR_ARROW)
dark_grey = p.Surface((600, 606))
rect = dark_grey.get_rect(topleft=(200, 10))
dark_grey.fill((95,95,95))
self.toDrawNext.append([dark_grey, rect])
x = 200
y = 200
info = self.small_font.render(data['window']['info'][0], True, (0,0,0))
text_rect = info.get_rect(topleft=(210,30))
self.toDrawNext.append([info, text_rect])
info = self.small_font.render(data['window']['info'][1], True, (0,0,0))
text_rect = info.get_rect(topleft=(210,55))
self.toDrawNext.append([info, text_rect])
info = self.small_font.render('Owner:', True, (255,0,255))
text_rect = info.get_rect(topleft=(210,90))
self.toDrawNext.append([info, text_rect])
info = self.small_font.render('Health:', True, (255,0,255))
text_rect = info.get_rect(topleft=(210,110))
self.toDrawNext.append([info, text_rect])
info = self.small_font.render('Level:', True, (255,0,255))
text_rect = info.get_rect(topleft=(210,130))
self.toDrawNext.append([info, text_rect])
info = self.small_font.render(data['window']['4th_info'][0] + ':', True, (255,0,255))
big_text_rect = info.get_rect(topleft=(210,150))
self.toDrawNext.append([info, big_text_rect])
right = big_text_rect.topright[0] + 30
info = self.small_font.render(data['window']['owner'], True, data['window']['color'])
text_rect = info.get_rect(topleft=(right,90))
self.toDrawNext.append([info, text_rect])
info = self.small_font.render(str(data['window']['health'][0]) + '/' + str(data['window']['health'][1]), True, (0,0,0))
text_rect = info.get_rect(topleft=(right,110))
self.toDrawNext.append([info, text_rect])
info = self.small_font.render(str(data['window']['level']), True, (0,0,0))
text_rect = info.get_rect(topleft=(right,130))
self.toDrawNext.append([info, text_rect])
info = self.small_font.render(data['window']['4th_info'][1], True, (0,0,0))
text_rect = info.get_rect(topleft=(right,150))
self.toDrawNext.append([info, text_rect])
for Y in range(len(data['window']['options'])):
black = p.Surface((600, 2))
black_rect = black.get_rect(topleft=(200,y+Y*40))
grey = p.Surface((600, 44))
rect = grey.get_rect(topleft=(200, y+Y*40))
grey.fill((155,155,155))
mouse = p.mouse.get_pos()
if rect.collidepoint(mouse):
grey.fill((250, 250, 255))
self.toDrawNext.append([grey, rect])
self.toDrawNext.append([black, black_rect])
name = self.medium_font.render(data['window']['options'][Y], True, (0,0,0))
text_rect = name.get_rect(midtop=(500, y+Y*40+5))
self.toDrawNext.append([name, text_rect])
def Network_draw_innpc_window(self, data):
grey = p.Surface((610, 618))
large_rect = grey.get_rect(topleft=(195, 4))
grey.fill((128,128,128))
self.toDrawNext.append([grey, large_rect])
dark_grey = p.Surface((600, 606))
rect = dark_grey.get_rect(topleft=(200, 10))
dark_grey.fill((95,95,95))
self.toDrawNext.append([dark_grey, rect])
x = 210
y = 30
for Y, thing in enumerate(data['window']['info']):
info = self.small_font.render(thing, True, (0,0,0))
text_rect = info.get_rect(topleft=(x, y + Y*15))
self.toDrawNext.append([info, text_rect])
x = 200
y = 200
for Y in range(len(data['window']['options'])):
black = p.Surface((600, 2))
black_rect = black.get_rect(topleft=(200,y+Y*40))
grey = p.Surface((600, 44))
rect = grey.get_rect(topleft=(200, y+Y*40))
grey.fill((155,155,155))
mouse = p.mouse.get_pos()
if rect.collidepoint(mouse):
grey.fill((250, 250, 255))
self.toDrawNext.append([grey, rect])
self.toDrawNext.append([black, black_rect])
name = self.medium_font.render(data['window']['options'][Y], True, (0,0,0))
text_rect = name.get_rect(midtop=(500, y+Y*40+5))
self.toDrawNext.append([name, text_rect])
def Network_WARNING_outdated_client(self, data):
info = self.medium_font.render('WARNING: Outdated Client', True, (255,0,0))
text_rect = info.get_rect(midbottom=(400,600))
box = p.Surface((text_rect.width + 10, 85))
box.fill((255,255,255))
rect = box.get_rect(midbottom=(400, 650))
self.toDrawNext.append([box, rect])
self.toDrawNext.append([info, text_rect])
info = self.medium_font.render('Server: %s - Client: %s' % (data['version'], self.version), True, (255,0,0))
text_rect = info.get_rect(midbottom=(400,635))
self.toDrawNext.append([info, text_rect])
def Network_WARNING_outdated_server(self, data):
info = self.medium_font.render('WARNING: Outdated Server', True, (255,0,0))
text_rect = info.get_rect(midbottom=(400,600))
box = p.Surface((text_rect.width + 10, 85))
box.fill((255,255,255))
rect = box.get_rect(midbottom=(400, 650))
self.toDrawNext.append([box, rect])
self.toDrawNext.append([info, text_rect])
info = self.medium_font.render('Server: %s - Client: %s' % (data['version'], self.version), True, (255,0,0))
text_rect = info.get_rect(midbottom=(400,635))
self.toDrawNext.append([info, text_rect])
def Network_display_host(self, data):
x, y, width, height = 700, 0, 300, 50
# Check if the dropdown is clicked
mouse_pos = p.mouse.get_pos()
mouse = p.mouse.get_pressed()
if self.dropdown_open:
# Display the dropdown options
for i, option in enumerate(self.gamemodes):
option_rect = pygame.Rect(x, y + (height * (i+1)), width, height)
text_surface = self.medium_font.render(option, True, (255, 255, 255))
text_rect = text_surface.get_rect(center=option_rect.center)
surf = p.Surface((width, height), p.SRCALPHA)
if option_rect.collidepoint(mouse_pos):
surf.fill((200,200,200,200))
else:
surf.fill((128,128,128,200))
self.toDrawNext.append((surf, option_rect))
self.toDrawNext.append((text_surface, text_rect))
if option_rect.collidepoint(mouse_pos) and mouse[0]:
# Change the selected option
self.gamemode = option
self.Send({"action": "change_gamemode", "gamemode": self.gamemode})
text_surface = self.medium_font.render(('Gamemode' if self.dropdown_open else self.gamemode), True, (255, 255, 255))
text_rect = text_surface.get_rect(center=self.dropdown_rect.center)
surf = p.Surface((width, height), p.SRCALPHA)
if self.dropdown_rect.collidepoint(mouse_pos):
if self.dropdown_open:
surf.fill((200,200,200))
else:
surf.fill((200,200,200,200))
else:
if self.dropdown_open:
surf.fill((128,128,128))
else:
surf.fill((128,128,128,200))
self.toDrawNext.append((surf, self.dropdown_rect))
self.toDrawNext.append((text_surface, text_rect))
def Network_connected(self, data):
"""
Network_connected runs when you successfully connect to the server
"""
self.Send({'action':'version', 'version':self.version})
self.Send({'action':'init', 'username':self.username, 'status':'JG', 'color':self.color, 'skin':self.skin, 'xp':self.xp})
__main__.stop_loading_circle = True
print("Joined game")
p.mixer.music.stop()
def Network_error(self, data):
"""
Network_error runs when there is a server error
"""
print('error:', data['error'][1])
self.ShutDown()
def Network_disconnected(self, data):
"""
Network_disconnected runs when you disconnect from the server
"""
self.ShutDown()
def Network_kicked(self, data):
self.ShutDown()
p.quit()
exit()
def main(screen, clock, username, version, userInfo, ip, port=5555, musicPlaying=True):
global running, cursor, music_playing
running = True
cursor = p.cursors.Cursor(p.SYSTEM_CURSOR_ARROW)
music_playing = musicPlaying
print(ip)
cursor = p.cursors.Cursor(pygame.SYSTEM_CURSOR_ARROW)
client = MyGameClient(ip, port, screen, clock, username, version, userInfo['color'], userInfo['skin'], userInfo['xp'])
while running:
client.update()
client.ShutDown()
p.mixer.music.stop()
return music_playing
if __name__ == '__main__':
print('You probably want to run main.py instead of this.')
hacking.py
from building import *
def kick(self, playername):
for p in self.server.players:
if p.username == playername:
p.Send({'action':'kicked'})
print('Kicked ' + playername)
del self.server.players[playername]
def makeWallsFall(self):
self.server.upwall.count = 10
self.server.leftwall.count = 10
def kill(self, playername):
for p in self.server.players:
if p.username == playername:
break
p = p.character
p.getHurt(300, self.character, 0, 0, msg="<Attacker> killed <Victim> using cheats")
def win(self):
self.server.terminate(self)
def message(self, theMessage, color=(0,0,0)):
for p in self.server.players:
p.message = message
p.message_color = color
p.message_count = 160
def redybarb(self):
self.character.attack = 200
self.character.has_shield = True
makeWallsFall(self)
BarbarianRaid(self.server, 10)
InnPC.py
import pygame
import toolbox as t
import random as r
from building import *
from events import *
INNSTART = 300
INNEND = 900
def get_innpc(inn):
npcs = [Botanist, Merchant, Rancher, Alchemist]
if inn.level > 1:
npcs.extend([Mayor, Repairer, Builder, Advanced_balloonist])
bds = inn.owner.get_buildings()
for NPC in npcs[:]:
if NPC.building in [bd.__class__ for bd in bds]:
npcs.remove(NPC)
try:
return r.choice(npcs)(inn)
except:
return
class Builders(Building):
dimensions = (490 * 0.8, 490 * 0.8)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building is for the Builder. As long as this buildings isn\'t broken, all the buildings you buy will be smaller.', '')
self.type = 'Builder\'s'
self.health = self.max_health = 300
self.dimensions = type(self).dimensions
self.post_init(rect)
def minute(self, player):
if not self.server.fallen:
if player.food > 90:
player.food -= 90
player.channel.message = 'You added a minute till the Walls fall.'
player.channel.message_color = (255, 205, 0)
player.channel.message_count = 160
self.server.upwall.count += 30*60
self.server.leftwall.count += 30*60
self.server.barbarian_count += 30*60
else:
player.channel.message = 'You don\'t have enough food to do this.'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
else:
player.channel.message = 'The Walls have already fallen!'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
if self.server.fallen:
channel.window = {'text':self.info,
'4th_info':('Walls Fallen', 'True'),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.Out)],
'simp':('Heal', 'Out')}
else:
channel.window = {'text':self.info,
'4th_info':('Time till the Walls fall', self.server.getTime()),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.minute), (2, self.Out)],
'simp':('Heal', 'Add a minute till the Walls fall (90 food)', 'Out')}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'4th_info':('Walls Fallen', str(self.server.fallen)),
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 food)', 'Out']}
class RepairCenter(Building):
dimensions = (490, 490)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building is for the Repairer, so that you can repair your village with ease!', '')
self.type = 'Repair Center'
self.health = self.max_health = 290
self.dimensions = type(self).dimensions
self.post_init(rect)
def repair(self, player):
if player.gold > 49:
player.gold -= 50
player.channel.message = 'Your village has been repaired for 50 gold.'
player.channel.message_color = (255, 205, 0)
player.channel.message_count = 160
for b in player.channel.get_buildings():
b.health = b.max_health
else:
player.channel.message = 'You don\'t have enough gold!'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Buildings needing repair', str(len([b for b in channel.get_buildings() if b.health < b.max_health]))),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.repair), (2, self.Out)],
'simp':('Heal', 'Repair Village (50 gold)', 'Out')}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'4th_info':('Buildings needing repair', str(len([b for b in channel.get_buildings() if b.health < b.max_health]))),
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 food)', 'Out']}
class AdvancedBalloonistBuilding(Building):
dimensions = (490, 490)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building is for the Advanced Balloonist NPC, so that you can upgrade your shot speed easily.', '')
self.type = 'Advanced Balloonist'
self.health = self.max_health = 300
self.dimensions = type(self).dimensions
self.post_init(rect)
def speedgun(self, player):
if player.shot_speed != 1:
if player.gold > 279:
player.gold -= 280
player.channel.message = 'You increased your shoot speed for 280 gold.'
player.channel.message_color = (255, 205, 0)
player.channel.message_count = 160
player.shot_speed -= 1
else:
player.channel.message = 'You don\'t have enough gold to do this.'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
else:
player.channel.message = 'Your balloon gun is already at its max! (Nobody\'s gonna stop you now)'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Shot Speed', str(16-channel.character.shot_speed)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.speedgun), (2, self.Out)],
'simp':('Heal', '+ Shot Speed (280 gold)', 'Out')}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'4th_info':('Shot Speed', str(16-channel.character.shot_speed)),
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 food)', 'Out']}
class TownHall(Building):
dimensions = (560, 540)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building has 500 HP! It\'ll also repair itself fully if it hasn\'t been attacked in a minute.', '')
self.type = 'Town Hall'
self.health = self.max_health = 500
self.dimensions = type(self).dimensions
self.count = 0
self.post_init(rect)
def update(self):
super().update()
if self.count:
self.count -= 1
if not self.count:
self.health = self.max_health
def getHurt(self, damage, attacker):
super().getHurt(damage, attacker)
self.count = 1800
class AlchemistsLab(Building):
dimensions = (490, 490)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building is for the Alchemist, so that you can always trade with it.', '')
self.type = 'Alchemist\'s Lab'
self.health = self.max_health = 220
self.dimensions = type(self).dimensions
self.post_init(rect)
def rate1(self, player):
if player.gold > 9:
mine = None
for b in self.owner.get_buildings():
if b.__class__.__name__ == 'MinersGuild':
mine = b.miner.farm
break
if mine is None:
player.channel.message = 'Get a Miner\'s Guild first!'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
self.Out(player)
return
if not mine.production == 250:
player.gold -= 10
player.channel.message = 'You have increased your Gold Discovery Rate by 10 for 10 gold.'
player.channel.message_color = (255,205,0)
player.channel.message_count = 150
mine.production -= 10
if mine.production < 250:
mine.production = 250
else:
player.channel.message = 'The Gold Discovery Rate is at its maximum!'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
else:
player.channel.message = 'You don\'t have enough gold!'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
self.Out(player)
def rate2(self, player):
if player.gold > 149:
mine = None
for b in self.owner.get_buildings():
if b.__class__.__name__ == 'MinersGuild':
mine = b.miner.farm
break
if mine is None:
player.channel.message = 'Get a Miner\'s Guild first!'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
self.Out(player)
return
if not mine.production == 250:
player.gold -= 150
player.channel.message = 'You have increased your Gold Discovery Rate by 250 for 150 gold.'
player.channel.message_color = (255,205,0)
player.channel.message_count = 150
mine.production -= 250
if mine.production < 250:
mine.production = 250
else:
player.channel.message = 'The Gold Discovery Rate is at its maximum!'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
else:
player.channel.message = 'You don\'t have enough gold!'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Gold', str(channel.character.gold)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.rate1), (2, self.rate2), (3, self.Out)],
'simp':('Heal', 'Increase Gold Discovery Rate by 10 (10 gold)', 'Increase Gold Discovery Rate by 250 (150 gold)', 'Out')}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'4th_info':('Gold', str(channel.character.gold)),
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 food)', 'Out']}
class Ranch(Building):
dimensions = (490, 490)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building is for the Rancher, so that you can always trade with it.', '')
self.type = 'Ranch'
self.health = self.max_health = 220
self.dimensions = type(self).dimensions
self.post_init(rect)
def rate1(self, player):
if player.food > 9:
farm = None
for b in self.owner.get_buildings():
if b.__class__.__name__ == 'FarmersGuild':
farm = b.farmer.farm
break
if farm is None:
player.channel.message = 'Get a Farmer\'s Guild first!'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
self.Out(player)
return
if not farm.production == 250:
player.food -= 10
player.channel.message = 'You have increased your Food Production Rate by 10 for 10 food.'
player.channel.message_color = (255,205,0)
player.channel.message_count = 150
farm.production -= 10
if farm.production < 250:
farm.production = 250
else:
player.channel.message = 'The Food Production Rate is at its maximum!'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
else:
player.channel.message = 'You don\'t have enough food!'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
self.Out(player)
def rate2(self, player):
if player.food > 149:
farm = None
for b in self.owner.get_buildings():
if b.__class__.__name__ == 'FarmersGuild':
farm = b.farmer.farm
break
if farm is None:
player.channel.message = 'Get a Farmer\'s Guild first!'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
self.Out(player)
return
if not farm.production == 250:
player.food -= 150
player.channel.message = 'You have increased your Food Production Rate by 250 for 150 food.'
player.channel.message_color = (255,205,0)
player.channel.message_count = 150
farm.production -= 250
if farm.production < 250:
farm.production = 250
else:
player.channel.message = 'The Food Production Rate is at its maximum!'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
else:
player.channel.message = 'You don\'t have enough food!'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Food', str(channel.character.food)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.rate1), (2, self.rate2), (3, self.Out)],
'simp':('Heal', 'Increase Food Production Rate by 10 (10 food)', 'Increase Food Production Rate by 250 (150 food)', 'Out')}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'4th_info':('Gold', str(channel.character.gold)),
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 food)', 'Out']}
class BotanistsLab(Building):
dimensions = (490, 490)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building is for the Botanist, so that you can always buy from it.', '')
self.type = 'Botanist\'s Lab'
self.health = self.max_health = 220
self.dimensions = type(self).dimensions
self.post_init(rect)
def spiky_bush(self, player):
if player.food > 0:
player.food -= 1
player.channel.message = 'You have bought a spiky bush for 1 food.'
player.spiky_bushes += 1
player.channel.message_color = (255,205,0)
player.channel.message_count = 150
player.garden_xp += 1
else:
player.channel.message = 'You don\'t have enough food to buy this!'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
self.Out(player)
def sappling(self, player):
if player.food > 6:
player.food -= 7
player.channel.message = 'You have bought a sappling for 7 food.'
player.channel.text = 'Press c to place sappling'
player.channel.message_color = (255,205,0)
player.channel.message_count = 150
player.garden_xp += 20
else:
player.channel.message = 'You don\'t have enough food to buy this!'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
self.Out(player)
def vine(self, player):
if player.food > 14:
player.food -= 15
player.channel.message = 'You have bought an invasive vine for 15 food.'
player.channel.text = 'Press c to place invasive vine'
player.channel.message_color = (255,205,0)
player.channel.message_count = 150
else:
player.channel.message = 'You don\'t have enough food to buy this!'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Gardening XP', str(channel.character.garden_xp)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.sappling), (2, self.spiky_bush), (3, self.Out)],
'simp':('Heal', 'Buy a sappling (7 food)', 'Buy a spiky bush (1 food)', 'Out')}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'4th_info':('Gardening XP', str(channel.character.garden_xp)),
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 food)', 'Out']}
class Market(Building):
dimensions = (490, 490)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building is for the Merchant, so that you can always trade', 'gold for food and food for gold.')
self.type = 'Market'
self.health = self.max_health = 220
self.dimensions = type(self).dimensions
self.post_init(rect)
def tradegold(self, player):
if player.food > 9:
player.food -= 10
player.gold += 10
player.channel.message = 'You have traded 10 food for 10 gold.'
player.channel.message_color = (255,205,0)
player.channel.message_count = 150
else:
player.channel.message = 'You don\'t have enough food to trade!'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
self.Out(player)
def tradefood(self, player):
if player.gold > 9:
player.gold -= 10
player.food += 10
player.channel.message = 'You have traded 10 gold for 10 food.'
player.channel.message_color = (255,205,0)
player.channel.message_count = 150
else:
player.channel.message = 'You don\'t have enough gold to trade!'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Resources', str(self.owner.character.gold) + ' gold, ' + str(self.owner.character.food) + ' food'),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.tradegold), (2, self.tradefood), (3, self.Out)],
'simp':('Heal', 'Trade 10 food for 10 gold', 'Trade 10 gold for 10 food', 'Out')}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'4th_info':('Resources', str(self.owner.character.gold) + ' gold, ' + str(self.owner.character.food) + ' food'),
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 food)', 'Out']}
class RetiredBarbarianOutpost(Building):
dimensions = (600, 490)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building is for the Retired Barbarian.', '')
self.type = 'Retired Barbarian Outpost'
self.health = self.max_health = 160
self.dimensions = type(self).dimensions
self.post_init(rect)
def crossbow(self, player):
if player.barbshoot_cooldown >= 0:
player.channel.message = 'You already have a barbarian crossbow!'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
elif player.food > 99:
player.food -= 100
player.channel.message = 'You bought a barbarian crossbow for 100 food.'
player.channel.message_color = (255, 205, 0)
player.channel.message_count = 160
player.barbshoot_cooldown = 50
else:
player.channel.message = 'You don\'t have enough food to buy this.'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
self.Out(player)
def shield(self, player):
if player.has_shield:
player.channel.message = 'You already have a shield!'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
elif player.food > 159:
player.food -= 160
player.channel.message = 'You bought a Barbarian Shield for 160 food.'
player.channel.message_color = (255, 205, 0)
player.channel.message_count = 160
player.has_shield = True
else:
player.channel.message = 'You don\'t have enough food to buy this.'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
channel.window = {'text':self.info,
'4th_info':('Need Shield', str(not channel.character.has_shield)),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.shield), (2, self.crossbow), (3, self.Out)],
'simp':('Heal', 'Buy a shield (160 food)', 'Buy a barbarian crossbow (100 food)', 'Out')}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'4th_info':('Need Shield', str(not channel.character.has_shield)),
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 food)', 'Out']}
class AdventuringCenter(Building):
dimensions = (510, 400)
def __init__(self, server, x, y, owner, rect):
Building.__init__(self, server, x, y, owner)
self.info = ('This building is for the Adventurer. Having this building is the best.', '')
self.type = 'Adventuring Center'
self.health = self.max_health = 300
self.dimensions = type(self).dimensions
self.post_init(rect)
def barbarianRaid(self, player):
if player.gold > 44:
player.gold -= 45
BarbarianRaid(self.server)
else:
player.channel.message = 'You don\'t have enough gold!'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
self.Out(player)
def barbarianRaidHuge(self, player):
if player.gold > 99:
player.gold -= 100
BarbarianRaid(self.server, 19 + randint(0, 4))
else:
player.channel.message = 'You don\'t have enough gold!'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
self.Out(player)
def end(self, player):
for p in self.server.players:
p.message = player.channel.username + ' has ended the current event.'
p.message_color = (255, 205, 0)
p.message_count = 160
p.to_send.append({'action':'music_change', 'music':'village'})
self.server.event = Event(self.server)
self.Out(player)
def open_window(self, channel):
if self.state == 'alive':
channel.in_window = True
if self.server.event.__class__ != Event:
channel.window = {'text':self.info,
'4th_info':('Current Event', self.server.event.__class__.__name__),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.end), (2, self.Out)],
'simp':('Heal', 'End Current Event (Free)', 'Out')}
else:
channel.window = {'text':self.info,
'4th_info':('Buildings needing repair', str(len([b for b in channel.get_buildings() if b.health < b.max_health]))),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'options':[(0, self.heal), (1, self.barbarianRaid), (2, self.barbarianRaidHuge), (3, self.Out)],
'simp':('Heal', 'Trigger a Barbarian Raid (45 gold)', 'Trigger a huge Barbarian Raid (100 gold)', 'Out')}
elif self.state == 'broken':
channel.in_window = True
channel.window = {'text':('This building is broken.', ''),
'health':(self.health, self.max_health),
'building':self,
'level':self.level,
'4th_info':('Buildings needing repair', str(len([b for b in channel.get_buildings() if b.health < b.max_health]))),
'options':[(0, self.clear), (1, self.Out)],
'simp':['Clear (2 food)', 'Out']}
class InnPC():
def __init__(self, inn):
self.inn = inn
self.type = type(self).__name__.replace('_', ' ').title()
self.server = inn.server
self.angle = 0
self.x = self.inn.x + r.randint(-100, 100)
self.y = self.inn.y + 130
self.health = 100
p = self.inn.owner
p.message = 'The %s has arrived!' % self.type
p.message_count = 160
p.message_color = (128,0,128)
self.count = r.randint(30*60*1, 30*60*5)
self.rect = pygame.Surface((50, 50)).get_rect(center=(self.x, self.y))
self.building = None
@property
def window(self):
return {'text':(self.type + ':', 'Hello, there!'),
'options':(('Out', self.Out),)}
def Out(self, channel):
channel.in_window = False
channel.in_innpc_window = False
channel.Send({'action':'sound', 'sound':'cw'})
def update(self):
self.count -= 1
if self.count == 0:
self.depart()
self.angle = t.getAngle(self.x, self.y, self.inn.owner.character.x, self.inn.owner.character.y)
for p in self.server.players:
if not p.pending:
p.to_send.append({'action':'draw_InnPC',
'type':self.type,
'coords':(p.character.get_x(self), p.character.get_y(self)),
'angle':self.angle,
'color':self.inn.owner.color,
'health':self.health})
def depart(self, comeback=True):
self.inn.NPC = None
p = self.inn.owner
p.message = 'The %s has departed.' % self.type
p.message_count = 160
p.message_color = (128,0,128)
if comeback:
self.inn.count = r.randint(INNSTART, INNEND)
if self.inn.level > 1 and self.inn.count > 150:
self.inn.count -= 150
class Botanist(InnPC):
building = BotanistsLab
def __init__(self, inn):
super().__init__(inn)
self.cost = (0, 70)
self.building = BotanistsLab
@property
def window(self):
return {'text':(self.type + ':', 'Hello, there! I sell sapplings, that will grow into any of the trees that the game started with!',
'I also sell spiky bushes. You might have heard of crates, they are the same size except that',
'people can go through the spiky bush, it\'s just that they take damage.'),
'options':(('Buy a sappling (7 food)', self.sappling), ('Buy a spiky bush (1 food)', self.spiky_bush), ('Out', self.Out))}
def spiky_bush(self, channel):
if channel.character.food > 0:
channel.character.food -= 1
channel.message = 'You have bought a spiky bush for 1 food.'
channel.character.spiky_bushes += 1
channel.message_color = (255,205,0)
channel.message_count = 150
channel.character.garden_xp += 1
else:
channel.message = 'You don\'t have enough food to buy this!'
channel.message_color = (255,0,0)
channel.message_count = 150
self.Out(channel)
def sappling(self, channel):
if channel.character.food > 6:
channel.character.food -= 7
channel.message = 'You have bought a sappling for 7 food.'
channel.text = 'Press c to place sappling'
channel.message_color = (255,205,0)
channel.message_count = 150
channel.character.garden_xp += 20
else:
channel.message = 'You don\'t have enough food to buy this!'
channel.message_color = (255,0,0)
channel.message_count = 150
self.Out(channel)
class Alchemist(InnPC):
building = AlchemistsLab
def __init__(self, inn):
super().__init__(inn)
self.cost = (80, 0)
self.building = AlchemistsLab
@property
def window(self):
return {'text':(self.type + ':', 'Greetings. I can change stone into gold. I might do so for you, for a little money.'),
'options':(('Increase Gold Discovery Rate by 10 (10 gold)', self.rate1), ('Increase Gold Discovery Rate by 250 (150 gold)', self.rate2), ('Out', self.Out))}
def rate1(self, channel):
if channel.character.gold > 9:
mine = None
for b in self.inn.owner.get_buildings():
if b.__class__.__name__ == 'MinersGuild':
mine = b.miner.farm
break
if mine is None:
player.channel.message = 'Get a Miner\'s Guild first!'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
self.Out(player)
return
if mine and not mine.production == 250:
channel.character.gold -= 10
channel.message = 'You have increased your Gold Discovery Rate by 10 for 10 gold.'
channel.message_color = (255,205,0)
channel.message_count = 150
mine.production -= 10
if mine.production < 250:
mine.production = 250
else:
channel.message = 'The Gold Discovery Rate is at its maximum!'
channel.message_color = (0,0,255)
channel.message_count = 150
else:
channel.message = 'You don\'t have enough gold!'
channel.message_color = (255,0,0)
channel.message_count = 150
self.Out(channel)
def rate2(self, channel):
if channel.character.gold > 149:
mine = None
for b in self.inn.owner.get_buildings():
if b.__class__.__name__ == 'MinersGuild':
mine = b.miner.farm
break
if mine is None:
player.channel.message = 'Get a Miner\'s Guild first!'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
self.Out(player)
return
if mine and not mine.production == 250:
channel.character.gold -= 150
channel.message = 'You have increased your Gold Discovery Rate by 250 for 150 gold.'
channel.message_color = (255,205,0)
channel.message_count = 150
mine.production -= 250
if mine.production < 250:
mine.production = 250
else:
channel.message = 'The Gold Discovery Rate is at its maximum!'
channel.message_color = (0,0,255)
channel.message_count = 150
else:
channel.message = 'You don\'t have enough gold!'
channel.message_color = (255,0,0)
channel.message_count = 150
self.Out(channel)
class Rancher(InnPC):
building = Ranch
def __init__(self, inn):
super().__init__(inn)
self.cost = (0, 80)
self.building = Ranch
@property
def window(self):
return {'text':(self.type + ':', 'Howdy, folks! I know better techniques for growing food. I could sell some of those ideas, if you want.'),
'options':(('Increase Food Production Rate by 10 (10 food)', self.rate1), ('Increase Food Production Rate by 250 (150 food)', self.rate2), ('Out', self.Out))}
def rate1(self, channel):
if channel.character.food > 9:
farm = None
for b in self.inn.owner.get_buildings():
if b.__class__.__name__ == 'FarmersGuild':
farm = b.farmer.farm
break
if farm is None:
player.channel.message = 'Get a Farmer\'s Guild first!'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
self.Out(player)
return
if not farm.production == 250:
channel.character.food -= 10
channel.message = 'You have increased your Food Production Rate by 10 for 10 food.'
channel.message_color = (255,205,0)
channel.message_count = 150
farm.production -= 10
if farm.production < 250:
farm.production = 250
else:
channel.message = 'The Food Production Rate is at its maximum!'
channel.message_color = (0,0,255)
channel.message_count = 150
else:
channel.message = 'You don\'t have enough food!'
channel.message_color = (255,0,0)
channel.message_count = 150
self.Out(channel)
def rate2(self, channel):
if channel.character.food > 149:
farm = None
for b in self.inn.owner.get_buildings():
if b.__class__.__name__ == 'FarmersGuild':
farm = b.farmer.farm
break
if farm is None:
player.channel.message = 'Get a Farmer\'s Guild first!'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
self.Out(player)
return
if farm and not farm.production == 250:
channel.character.food -= 150
channel.message = 'You have increased your Food Production Rate by 250 for 150 food.'
channel.message_color = (255,205,0)
channel.message_count = 150
farm.production -= 250
if farm.production < 250:
farm.production = 250
else:
channel.message = 'The Food Production Rate is at its maximum!'
channel.message_color = (0,0,255)
channel.message_count = 150
else:
channel.message = 'You don\'t have enough food!'
channel.message_color = (255,0,0)
channel.message_count = 150
self.Out(channel)
class Merchant(InnPC):
building = Market
def __init__(self, inn):
super().__init__(inn)
self.building = Market
self.cost = (27, 27)
@property
def window(self):
return {'text':(self.type + ':', 'Hello, there! Give me food or gold and I\'ll give you the other.'),
'options':(('Trade 10 food for 10 gold', self.gold), ('Trade 10 gold for 10 food', self.food), ('Out', self.Out))}
def gold(self, channel):
if channel.character.food > 9:
channel.character.food -= 10
channel.character.gold += 10
channel.message = 'You have traded 10 food for 10 gold.'
channel.message_color = (255,205,0)
channel.message_count = 150
else:
channel.message = 'You don\'t have enough food to trade.'
channel.message_color = (255,0,0)
channel.message_count = 150
self.Out(channel)
def food(self, channel):
if channel.character.gold > 9:
channel.character.gold -= 10
channel.character.food += 10
channel.message = 'You have traded 10 gold for 10 food.'
channel.message_color = (255,205,0)
channel.message_count = 150
else:
channel.message = 'You don\'t have enough gold to trade.'
channel.message_color = (255,0,0)
channel.message_count = 150
self.Out(channel)
class Mayor(InnPC):
building = TownHall
def __init__(self, inn):
super().__init__(inn)
self.building = TownHall
self.cost = (100, 50)
@property
def window(self):
return {'text':(self.type + ':', 'I\'m in politics. Maybe I\'m useless to you for now, but build me a town hall and you won\'t regret\nit. It\'ll have five hundred health and will repair itself.'),
'options':(('Out', self.Out),)}
class Retired_barbarian(InnPC):
building = RetiredBarbarianOutpost
def __init__(self, inn):
super().__init__(inn)
self.building = RetiredBarbarianOutpost
self.cost = (0, 20)
@property
def window(self):
return {'text':(self.type + ':', 'Hello. I\'m a barbarian. What\'s that? No, I mean I used to be a barbarian. I see you\'ve had the honor', 'of defeating the enemy tribe of my old one. As a reward, I am selling you some useful barbarian stuff.'),
'options':(('Out', self.Out), ('Buy a Barbarian Shield (160 food)', self.shield), ('Buy a Barbarian Crossbow (100 food)', self.crossbow))}
def shield(self, channel):
if channel.character.has_shield:
channel.message = 'You already have a shield!'
channel.message_color = (0,0,255)
channel.message_count = 150
elif channel.character.food > 159:
channel.character.food -= 160
channel.message = 'You bought a Barbarian Shield for 160 food.'
channel.message_color = (255,205,0)
channel.message_count = 150
channel.character.has_shield = True
else:
channel.message = 'You don\'t have enough food to buy this.'
channel.message_color = (255,0,0)
channel.message_count = 150
self.Out(channel)
def crossbow(self, channel):
if channel.character.barbshoot_cooldown >= 0:
channel.message = 'You already have a barbarian crossbow!'
channel.message_color = (0,0,255)
channel.message_count = 150
elif channel.character.food > 99:
channel.character.food -= 100
channel.message = 'You bought a barbarian crossbow for 100 food.'
channel.message_color = (255,205,0)
channel.message_count = 150
channel.character.barbshoot_cooldown = 50
else:
channel.message = 'You don\'t have enough food to buy this.'
channel.message_color = (255,0,0)
channel.message_count = 150
self.Out(channel)
class Adventurer(InnPC):
building = AdventuringCenter
def __init__(self, inn):
super().__init__(inn)
self.building = AdventuringCenter
self.cost = (40, 40)
@property
def window(self):
return {'text':(self.type + ':', 'Hello, I\'m the Adventurer. See for youself what I can do!'),
'options':(('Out', self.Out), ('Trigger a Barbarian Raid (45 gold)', self.barbarianRaid), ('Trigger a huge Babarian Raid (100 gold)', self.barbarianRaidHuge))}
def barbarianRaid(self, channel):
if channel.character.gold > 44:
channel.character.gold -= 45
BarbarianRaid(self.server)
else:
channel.message = 'You don\'t have enough gold to trigger a Barbarian Raid.'
channel.message_color = (255,0,0)
channel.message_count = 150
self.Out(channel)
def barbarianRaidHuge(self, channel):
if channel.character.gold > 99:
channel.character.gold -= 100
BarbarianRaid(self.server, 19 + randint(0, 4))
else:
channel.message = 'You don\'t have enough gold to trigger a huge Barbarian Raid.'
channel.message_color = (255,0,0)
channel.message_count = 150
self.Out(channel)
class Repairer(InnPC):
building = RepairCenter
def __init__(self, inn):
super().__init__(inn)
self.building = RepairCenter
self.cost = (10, 60)
@property
def window(self):
return {'text':(self.type + ':', 'Hello, there! Low on food? I\'ll repair everything in your village for just 50 gold!'),
'options':(('Repair Village (50 gold)', self.repair), ('Out', self.Out))}
def repair(self, channel):
if channel.character.gold > 49:
channel.character.gold -= 50
channel.message = 'You repaired your entire village for 50 gold.'
channel.message_color = (255,205,0)
channel.message_count = 150
for b in channel.get_buildings():
b.health = b.max_health
else:
channel.message = 'You don\'t have enough gold to repair your village.'
channel.message_color = (255,0,0)
channel.message_count = 150
self.Out(channel)
class Builder(InnPC):
building = Builders
def __init__(self, inn):
super().__init__(inn)
self.building = Builders
self.cost = (30, 0)
@property
def window(self):
base = {'text':(self.type + ':', 'As long as I\'m at the Inn, all the buildings you buy are smaller!')}
if self.inn.server.fallen:
base['options'] = (('Out', self.Out),)
else:
base['options'] = (('Add a minute till the Walls fall (100 food)', self.minute), ('Out', self.Out))
return base
def minute(self, channel):
if not self.inn.server.fallen:
if channel.character.food > 99:
channel.character.food -= 100
channel.message = 'You added a minute till the Walls fall.'
channel.message_color = (255,205,0)
channel.message_count = 150
self.inn.server.upwall.count += 30*60
self.inn.server.leftwall.count += 30*60
self.inn.server.barbarian_count += 30*60
else:
channel.message = 'You don\'t have enough food to do this.'
channel.message_color = (255,0,0)
channel.message_count = 150
else:
channel.message = 'The Walls have already fallen!'
channel.message_color = (0,0,255)
channel.message_count = 150
self.Out(channel)
class Advanced_balloonist(InnPC):
building = AdvancedBalloonistBuilding
def __init__(self, inn):
super().__init__(inn)
self.building = AdvancedBalloonistBuilding
self.cost = (140, 0)
@property
def window(self):
base = {'text':(self.type + ':', 'I\'m much more talented than the regular balloonist. You\'re lucky you got me!')}
base['options'] = (('+ Shot Speed (280 gold)', self.speedgun), ('Out', self.Out))
return base
def speedgun(self, channel):
player = channel.character
if player.shot_speed != 1:
if player.gold > 279:
player.gold -= 280
player.channel.message = 'You increased your shoot speed for 280 gold.'
player.channel.message_color = (255, 205, 0)
player.channel.message_count = 160
player.shot_speed -= 1
else:
player.channel.message = 'You don\'t have enough gold to do this.'
player.channel.message_color = (255,0,0)
player.channel.message_count = 150
else:
player.channel.message = 'Your balloon gun is already at its max! (Nobody\'s gonna stop you now)'
player.channel.message_color = (0,0,255)
player.channel.message_count = 150
self.Out(channel)
__ALL__ = ['AdventuringCenter',
'RetiredBarbarianOutpost',
'Market',
'BotanistsLab',
'Ranch',
'AlchemistsLab',
'TownHall',
'AdvancedBalloonistBuilding',
'RepairCenter',
'Builders',]
lobbyAvatar.py
import pygame as p
import toolbox as t
class LobbyAvatar():
def __init__(self, coords):
self.x, self.y = coords
self.x_flip = 500-self.x # Center on screen
self.y_flip = 325-self.y # (1000, 650)
self.angle = 0
self.speed = 8
self.ready = False
@property
def coords(self):
return self.x, self.y
def get_x(self, item):
if hasattr(item, 'x'):
return item.x + self.x_flip
return item + self.x_flip
def get_y(self, item):
if hasattr(item, 'y'):
return item.y + self.y_flip
return item + self.y_flip
def move_x(self, amount=None):
if amount is None:
amount = self.speed
self.x += amount
self.x_flip -= amount
if self.x < 50:
self.x -= amount
self.x_flip += amount
if self.x > 950:
self.x -= amount
self.x_flip += amount
def move_y(self, amount=None):
if amount is None:
amount = self.speed
self.y += amount
self.y_flip -= amount
if self.y < 50:
self.y -= amount
self.y_flip += amount
if self.y > 600:
self.y -= amount
self.y_flip += amount
def move(self):
x, y = t.getDir(self.angle, self.speed)
self.move_x(round(x))
self.move_y(round(y))
def HandleInput(self, keys, mouse):
if keys[p.K_SPACE]:
self.move()
self.angle = t.getAngle(500, 325, mouse[0], mouse[1])
menu.py
import pygame as p
import shelve
import math as m
import random
import webbrowser
from time import monotonic, sleep
import os
import sys
import pygame
import threading
import os
import re
import json
import zipfile2
import toolbox as t
from typer import Typing
from pygame.locals import *
from pymsgbox import *
import __main__
import requests, bs4
with open('../preferences.json', 'r') as fo:
preferences = json.loads(fo.read())
py = preferences.get('py', 'python')
def version_update(screen, clock, active):
global FINISHED, download_size, downloaded_bytes
grey_bar = p.Surface((800, 50))
grey_bar.fill((95, 95, 95))
grey_bar_rect = grey_bar.get_rect(center=(500, 300))
blue_bar_pos = grey_bar_rect.topleft
title = p.transform.scale(p.image.load('../assets/title page/attempt 1.png'), (500, 100))
fo = open('tips.json', 'r')
all_tips = json.loads(fo.read())
fo.close()
tips = []
for tip in all_tips['basic_tips']:
tip = font40.render(tip, True, (255,205,0))
tip_rect = tip.get_rect(midbottom=(500, 620))
tips.append((tip, tip_rect))
for tip in all_tips['rare_tips']:
tip = font40.render(tip, True, (255,0,128))
tip_rect = tip.get_rect(midbottom=(500, 620))
tips.append((tip, tip_rect))
random.shuffle(tips)
while True:
try:
perc = downloaded_bytes/download_size*100
except NameError:
perc = 0
title_rect = title.get_rect(midtop=(500, (10 * (m.sin(monotonic() * 2))) + 30)) # Update title location
for e in p.event.get():
if e.type == QUIT and confirm('Are you sure you want to cancel this update?', buttons=['Yes', 'No']) == 'Yes':
p.quit()
sys.exit()
screen.fill((255,255,255))
try:
blue_bar = p.Surface((perc/100*800, 50))
except:
blue_bar = p.Surface((0, 50))
blue_bar.fill((10, 10, 250))
try:
out_of = '%s / %s' % (downloaded_bytes, download_size)
except:
out_of = '%s / %s' % (0, '?')
screen.blit(title, title_rect)
screen.blit(grey_bar, blue_bar_pos)
screen.blit(blue_bar, blue_bar_pos)
perctext = p.font.SysFont('default', 40).render(str(round(perc, 1)) + ' %', True, (255,128,0))
perctextrect = perctext.get_rect(midtop=(500, 330))
screen.blit(perctext, perctextrect)
#perctext = p.font.SysFont('default', 30).render(out_of, True, (255,66,66))
#perctextrect = perctext.get_rect(midtop=(500, 400))
#screen.blit(perctext, perctextrect)
tip = tips[int((monotonic()/6)%len(tips))]
screen.blit(tip[0], tip[1])
p.display.set_caption('VillageWars %s --> %s Update: %s' % (__main__.__version__, active, out_of))
p.display.update()
clock.tick(60)
if FINISHED:
alert('Version %s has been installed\nsuccessfuly!' % active, title='VillageWars')
with open('../preferences.json', 'r') as fo:
preferences = json.loads(fo.read())
py = preferences.get('py', 'python')
path = preferences.get('path', [])
map = preferences.get('map', 'grass')
os.chdir('../../%s' % active)
with open('../preferences.json', 'w') as fo:
preferences = {'map':map, 'py':py, 'path':path}
fo.write(json.dumps(preferences))
p.quit()
os.system(py + ' -m main.py')
sys.exit()
def download_active_version(active):
global zipfile2
global FINISHED, download_size, downloaded_bytes
FINISHED = False
print('Sent files request')
res = requests.get('http://villagewars.pythonanywhere.com/download_active_version', stream=True)
res.raise_for_status()
download_size = int(res.headers['Content-length'])
downloaded_bytes = 0
fo = open('../run/downloads/new_version.zip', 'wb')
for chunk in res.iter_content(chunk_size=2048):
if chunk: # filter out keep-alive new chunks
len_chunk = len(chunk)
fo.write(chunk)
downloaded_bytes += len_chunk
fo.close() # Found commented out, i hope it wasn't important because it crashes the update
fo = zipfile2.ZipFile('../run/downloads/new_version.zip', 'r')
os.makedirs('../../%s' % active, exist_ok=True)
fo.extractall('../../%s' % active)
fo.close()
FINISHED = True
def load(result):
href = result['href']
name = result['name']
res = requests.get(href)
soup = bs4.BeautifulSoup(res.text, 'html.parser')
elem = soup.select('.mw-parser-output')[0]
return name + '\n' + elem.text
def load_results(search):
results = []
try:
res = requests.get('https://villagewars.fandom.com/wiki/Special:Search?query=%s&scope=internal&navigationSearch=true&so=trending' % search)
soup = bs4.BeautifulSoup(res.text, 'html.parser')
elements = soup.select('.unified-search__result__title') # All search responses
results = []
for elem in elements:
results.append({'href':elem.get('href'), 'name':elem.get('data-title')})
global guide_results, scroll
scroll = 0
guide_results = True
except:
alert('You need to be connected\nto the Internet.', title='VillageWars')
return results
def runMenu(screen, clock):
global mouse, click, keys, open_menu_surf, open_menu_hover_surf, options, tab, menu_space, font40, creds, font30, scroll, guide_results, carry_to
active = '0.0.1'
mouse = p.mouse.get_pos()
click = p.mouse.get_pressed()
keys = p.key.get_pressed()
width, height = screen.get_width(), screen.get_height()
font40 = p.font.SysFont('default', 40)
font200 = p.font.SysFont('default', 200)
font30 = p.font.SysFont('default', 30)
font100 = p.font.SysFont('default', 100)
title = p.transform.scale(p.image.load('../assets/title page/attempt 1.png'), (500, 100))
menu_space = 30
open_menu_surf = p.transform.scale(p.image.load('../assets/title page/open menu.png'), (22, 22))
open_menu_hover_surf = p.transform.scale(p.image.load('../assets/title page/open menu_hover.png'), (22, 22))
background = p.image.load('../assets/optional/{}.png'.format(random.randrange(3)))
background.set_alpha(180)
background_rect = background.get_rect(topright=(1000,0))
logIn_button = t.Button(screen, 'title page/log in to play.png', 'title page/log in to play_hover.png', 'title page/log in to play_down.png', midtop=(((width-menu_space)/2) + menu_space, 400))
#logInToPlay = p.image.load('../assets/title page/log in to play.png')
#logInToPlay_hover = p.image.load('../assets/title page/log in to play_hover.png')
#darker_surf = p.image.load('../assets/paused.png')
#credits_fade = p.image.load('../assets/title page/credits fade.png')
font80 = p.font.SysFont('default', 80)
tab = 'Home'
guide_results = True
fo = open('splash.txt')
splash = [s[:-1] for s in fo.readlines()]
fo.close()
splash = splash[random.randrange(len(splash))]
#splash = 'Ha!'
#print(len(splash))
splashFont = p.font.SysFont('default', 80-len(splash))
splash = splashFont.render(splash, True, (250,250,100))
creds = []
results = []
searcher = Typing(block=[])
scroll = 0
with open('../../version screenshots/version_info.json', 'r') as data_file:
version_data = json.loads(data_file.read())
active = version_data['active']
version_data = version_data['versions']
mag_glass = p.transform.scale(p.image.load('../assets/title page/search.png'), (30, 30))
search_activated = False
release_screenshots = {file[:-4]: p.transform.scale(p.image.load('../../version screenshots/' + file), (250, 162)) for file in os.listdir('../../version screenshots') if file != 'version_info.json'}
lovable_versions = [folder for folder in os.listdir('../../') if (not folder.endswith('.txt') and '.' in folder and folder in version_data)]
play_version_buttons = {}
for version in lovable_versions:
play_version_buttons[version] = t.Button(screen, 'play version.png', 'play version_hov.png', 'play version_down.png')
install_version_button = t.Button(screen, 'install_version.png', 'install_version_hov.png', 'install_version_down.png', topleft=(-1000, -650))
release_screenshots['default'] = p.transform.scale(p.image.load('../run/pre-downloaded/default.png'), (250, 162))
while True:
options = ['Home', 'Language', 'Statistics', 'Releases', 'Guide', 'Credits', 'Feedback']
options.remove(tab)
for event in pygame.event.get():
if event.type == QUIT:
p.quit()
sys.exit()
if tab == 'Guide' and event.type == KEYUP and event.key == K_RETURN and search_activated:
search = searcher.result
search_activated = False
results = load_results(search)
if event.type == KEYUP and event.key == K_F1:
p.mixer.music.load('../assets/sfx/menu.mp3')
p.mixer.music.play(-1, 0.0)
if tab == 'Guide' and event.type in (KEYDOWN, KEYUP) and event.key in (K_RSHIFT, K_LSHIFT):
searcher.shift()
if tab == 'Guide' and event.type in (KEYDOWN, KEYUP) and event.key in (K_RCTRL, K_LCTRL):
searcher.shift()
if tab == 'Guide' and event.type == KEYUP:
searcher.type(event)
if event.type == MOUSEBUTTONDOWN:
if tab in ('Guide', 'Releases'):
if event.button == 5:
scroll -= 20
elif event.button == 4:
if scroll < 0:
scroll += 20
if tab == 'Home' and logIn_button.handle_event(event):
do_tabs(screen, menu_space)
result = runLogIn(screen, clock)
if type(result) == dict:
return result
if tab == 'Releases':# and menu_space == 30:
for version in play_version_buttons:
button = play_version_buttons[version]
if button.x != 0 and button.handle_event(event):
os.chdir('../../%s/src' % version)
try:
os.system(py + ' -m VillageWarsClient')
except:
os.system(py + ' -m SuperShooterWar_startgame')
p.quit()
sys.exit()
#alert('Not Implemented.', title='VillageWars')
if active != __main__.__version__ and install_version_button.handle_event(event):
if confirm('A version installation is about to begin. Click OK to start it. This may take several minutes.', title='VillageWars') == 'OK':
thread = threading.Thread(target=download_active_version, args=[active])
thread.start()
version_update(screen, clock, active)
lovable_versions = [folder for folder in os.listdir('../../') if (not folder.endswith('.txt') and '.' in folder)]
play_version_buttons = {}
for version in lovable_versions:
play_version_buttons[version] = t.Button(screen, 'play version.png', 'play version_hov.png', 'play version_down.png')
mouse = p.mouse.get_pos()
click = p.mouse.get_pressed()
keys = p.key.get_pressed()
width, height = screen.get_width(), screen.get_height()
title_rect = title.get_rect(midtop=(((width-menu_space)/2) + menu_space, (10 * (m.sin(monotonic() * 2))) + 30 + scroll)) # Update title location
splash_rect = splash.get_rect(midtop=((100 * (m.sin((monotonic()+1) * 2.5))) + ((width-menu_space)/2) + menu_space, 180))
if tab == 'Home':
scroll = 0
screen.fill((255,255,255))
screen.blit(background, background_rect)
screen.blit(title, title_rect)
screen.blit(splash, splash_rect)
logIn_button.draw()
#if logIn_rect.collidepoint(mouse):
# screen.blit(logInToPlay_hover, logIn_rect)
# if click[0]:
#else:
# screen.blit(logInToPlay, logIn_rect)
if tab == 'Language':
screen.fill((255,255,255))
text_surf = font40.render('Not Implemented yet.', True, (0,0,0))
rect = text_surf.get_rect(midtop=((width-menu_space)//2+menu_space, 300 + scroll))
screen.blit(text_surf, rect)
if tab == 'Statistics':
screen.fill((255,255,255))
text_surf = font40.render('Not Implemented yet.', True, (0,0,0))
rect = text_surf.get_rect(midtop=((width-menu_space)//2+menu_space, 300 + scroll))
screen.blit(text_surf, rect)
if tab == 'Releases':
screen.fill((20,20,20))
#screen.blit(title, title_rect)
y = 100
for version in version_data:
if version == __main__.__version__:
text_surf = font40.render('Current version - %s - %s' % (version, version_data[version]['description']), True, (255,0,0))
rect = text_surf.get_rect(midtop=((width-menu_space)//2+menu_space, y + scroll))
screen.blit(text_surf, rect)
y += 50
if 'date' in version_data[version]:
text_surf = font40.render(version_data[version]['date'], True, (128,128,255))
rect = text_surf.get_rect(midtop=((width-menu_space)//2+menu_space, y + scroll))
screen.blit(text_surf, rect)
y += 40
screenshot = release_screenshots.get(version, release_screenshots['default'])
rect = screenshot.get_rect(midtop=((width-menu_space)//2+menu_space, y + scroll))
screen.blit(screenshot, rect)
y += rect.height + 50
if carry_to:
scroll = (-y) + height // 2 + 200
carry_to = False
if t.getVersionInt(active) > t.getVersionInt(__main__.__version__):
text_surf = font40.render('New updates available below!', True, (255,128,255))
rect = text_surf.get_rect(midtop=((width-menu_space)//2+menu_space, y + scroll))
screen.blit(text_surf, rect)
y += 80
elif t.getVersionInt(version) > t.getVersionInt(active): #__main__.__version__):
text_surf = font40.render('Version %s - %s' % (version, version_data[version]['description']), True, (255,200,200))
rect = text_surf.get_rect(midtop=((width-menu_space)//2+menu_space, y + scroll))
screen.blit(text_surf, rect)
y += 50
elif t.getVersionInt(version) > t.getVersionInt(__main__.__version__):
text_surf = font40.render('Version %s - %s' % (version, version_data[version]['description']), True, (255,255,255))
rect = text_surf.get_rect(midtop=((width-menu_space)//2+menu_space, y + scroll))
screen.blit(text_surf, rect)
y += 50
if 'date' in version_data[version]:
text_surf = font40.render(version_data[version]['date'], True, (255,128,128))
rect = text_surf.get_rect(midtop=((width-menu_space)//2+menu_space, y + scroll))
screen.blit(text_surf, rect)
y += 40
screenshot = release_screenshots.get(version, release_screenshots['default'])
rect = screenshot.get_rect(midtop=((width-menu_space)//2+menu_space, y + scroll))
screen.blit(screenshot, rect)
if version in play_version_buttons:
play_version_buttons[version].x = 700
play_version_buttons[version].y = y + 50 + scroll
play_version_buttons[version].draw()
if version == active:
install_version_button.x = 700
install_version_button.y = y + 50 + scroll
install_version_button.draw()
y += rect.height + 50
else:
text_surf = font40.render('Version %s - %s' % (version, version_data[version]['description']), True, (255,255,255))
rect = text_surf.get_rect(midtop=((width-menu_space)//2+menu_space, y + scroll))
screen.blit(text_surf, rect)
y += 50
if 'date' in version_data[version]:
text_surf = font40.render(version_data[version]['date'], True, (128,128,255))
rect = text_surf.get_rect(midtop=((width-menu_space)//2+menu_space, y + scroll))
screen.blit(text_surf, rect)
y += 40
screenshot = release_screenshots.get(version, release_screenshots['default'])
rect = screenshot.get_rect(midtop=((width-menu_space)//2+menu_space, y + scroll))
screen.blit(screenshot, rect)
if version in play_version_buttons:
play_version_buttons[version].x = 700
play_version_buttons[version].y = y + 50 + scroll
play_version_buttons[version].draw()
y += rect.height + 50
if version == active:
text_surf = font40.render('See below for upcoming releases!', True, (255,128,255))
rect = text_surf.get_rect(midtop=((width-menu_space)//2+menu_space, y + scroll))
screen.blit(text_surf, rect)
y += 80
#p.draw.rect(install_version_button.rect, (0,255,0))
if tab == 'Guide':
screen.fill((255,255,255))
#screen.blit(title, title_rect)
text_surf = font40.render('This is a work in progress.', True, (0,0,0))
rect = text_surf.get_rect(midtop=((width-menu_space)//2+menu_space, 100 + scroll))
screen.blit(text_surf, rect)
text_surf = font40.render('To view the output better, see villagewars.fandom.com', True, (0,0,0))
rect = text_surf.get_rect(midtop=((width-menu_space)//2+menu_space, 150 + scroll))
screen.blit(text_surf, rect)
if guide_results:
y = 250
for result in results:
text = font40.render(result['name'], True, (60,0,62))
rect = text.get_rect(topleft=(250, y + scroll))
if rect.collidepoint(mouse):
text = font40.render(result['name'], True, (120,0,124))
if click[0]:
guide_results = False
result_text = load(result)
results = []
screen.blit(text, rect)
y += 50
else:
y = 300
for i in result_text.split('\n'):
text_surf = font40.render(i, True, (0,0,0))
rect = text_surf.get_rect(topleft=(200, y + scroll))
screen.blit(text_surf, rect)
y += 50
surf = p.Surface((width, 50))
surf.fill((200,0,0))
screen.blit(surf, (0,0))
surf = p.Surface((width-menu_space-50, 40))
white_rect = surf.get_rect(topleft=(menu_space + 25, 5))
if white_rect.collidepoint(mouse):
if not search_activated:
surf.fill((240,240,240))
else:
surf.fill((255,255,255))
if click[0]:
search_activated = True
else:
surf.fill((255,255,255))
if click[0]:
search_activated = False
screen.blit(surf, white_rect)
mag_rect = mag_glass.get_rect(topleft=(width-65, 10))
if mag_rect.collidepoint(mouse):
scaled = p.transform.scale(mag_glass, (35, 35))
scaled_rect = scaled.get_rect(center=mag_rect.center)
screen.blit(scaled, scaled_rect)
if click[0]:
search = searcher.result
results = load_results(search)
else:
screen.blit(mag_glass, mag_rect)
if search_activated:
text = font40.render(searcher.text(), True, (0,0,0))
else:
if searcher.result:
text = font40.render(searcher.result, True, (0,0,0))
else:
text = font40.render('Click here to search', True, (188,188,188))
rect = text.get_rect(midleft=(white_rect.midleft[0] + 5, white_rect.midleft[1]))
screen.blit(text, rect)
if tab == 'Credits':
screen.fill((0,0,0))
if creds == []:
Credit.space = 650
creds.append(Credit('- Credits -', creds, font=font200, y=250))
creds.append(Credit('VillageWars', creds, font=font100, y=200))
creds.append(Credit('Creator: Aaron McCormick', creds, font=font40, y=100))
creds.append(Credit('Programming:', creds, font=font40, y=80))
creds.append(Credit('Surpervisor: Aaron McCormick', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Game Mechanics (Client + Server): Aaron McCormick', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Graphical Representation: pygame (module)', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Windows Messages: pymsgbox (module)', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Client-Server pumping: PodSixNet (module)', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Copy and paste with Windows clipboard: pyperclip (module)', creds, font=font40, y=80, rjust=True))
creds.append(Credit('Graphics:', creds, font=font40, y=80))
creds.append(Credit('Player Skins, Balloons(+ Water Droplets), Crates, TNT,', creds, font=font40, y=50, rjust=True))
creds.append(Credit(' Robots: Codakid Game Dev 2', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Map, Gates, Buildings, Building Borders: Aaron McCormick', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Walls, Trees, Spiky Bushes: opengameart.org', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Barbarians: Aaron McCormick, inspired by skin number 2', creds, font=font40, y=50, rjust=True))
creds.append(Credit(' (Codakid Game Dev 2)', creds, font=font40, y=80, rjust=True))
creds.append(Credit('Music and Sound Effects:', creds, font=font40, y=80))
creds.append(Credit('All Sound Effects (splashes, bump, explosions, shots):', creds, font=font40, y=50, rjust=True))
creds.append(Credit(' Codakid Game Dev 2', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Stepping Pebbles (Before the Walls fall): Matthew Pablo', creds, font=font40, y=50, rjust=True))
creds.append(Credit(' (opengameart.org)', creds, font=font40, y=50, rjust=True))
creds.append(Credit('After the Walls fall: opengameart.org', creds, font=font40, y=50, rjust=True))
creds.append(Credit('During the Barbarian Raid: opengameart.org', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Menu Music: opengameart.org', creds, font=font40, y=80, rjust=True))
creds.append(Credit('Exteral Server Management:', creds, font=font40, y=80))
creds.append(Credit('Programming: Aaron McCormick', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Support: Colin McCormick', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Module: Flask', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Application: Pythonanywhere.com', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Website: villagewars.pythonanywhere.com', creds, font=font40, y=80, rjust=True))
creds.append(Credit('Co-designers (Idea givers):', creds, font=font40, y=80))
creds.append(Credit('Caden McCormick, Lucas McComick, David McCormick,', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Angela McCormick, Charlie Garland, Owen Garland,', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Samuel Mawson, John Mawson, Colin McCormick,', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Nathan Dauner, Vincent Santoni, Jonathan Hostteter,', creds, font=font40, y=50, rjust=True))
creds.append(Credit('Gavin McCormick', creds, font=font40, y=50, rjust=True))
creds.append(Credit('If you would like to see your name here, send me an email', creds, font=font30, y=30, color=(255,100,255)))
creds.append(Credit('at [email protected] giving me ideas! Your idea won\'t', creds, font=font30, y=30, color=(255,100,255)))
creds.append(Credit('necessarily be added, but your name will be added here!', creds, font=font30, y=80, color=(255,100,255)))
#fo = shelve.open('database/data')
#users = dict(fo)
#fo.close()
print(1)
if __main__.INTERNET:
print(2)
try:
res = requests.get(__main__.flask_application + 'all_users')
res.raise_for_status()
print(3)
except:
__main__.INTERNET = False
else:
alert('You need to be connected\nto the Internet.', title='VillageWars')
tab = 'Home'
if __main__.INTERNET:
print(4)
users = res.text[4:]
users = eval(users)
creds.append(Credit('First %s Accounts:' % len(users), creds, font=font40, y=80))
for i, user in enumerate(list(users)):
if i+1 == len(users):
creds.append(Credit('%s) %s (%s)' % (i+1, user, users[user].get('name', 'No Name')), creds, font=font40, y=60, rjust=False))
else:
name = users[user].get('name', 'No Name')
if user in ('f', 'ModestNoob', 'ff'):
name = 'Aaron McCormick, test account'
if user == 'ProHacker':
name = 'Aaron McCormick, fake games account'
if user == 'Warpedillager':
name = 'Aaron McCormick, stunts account'
creds.append(Credit('%s) %s (%s)' % (i+1, user, name), creds, font=font40, y=50, rjust=False))
creds.append(Credit('...and new accounts are created every month!', creds, font=font40, y=200, rjust=True, color=(128,128,255)))
creds.append(Credit('Thank you everyone!', creds, font=font100, y=0, color=(255,255,5)))
for credit in creds:
credit.update(screen, keys=keys)
if tab == 'Feedback':
screen.fill((255,255,255))
text_surf = font40.render('To send feedback, email me at [email protected].', True, (0,0,0))
rect = text_surf.get_rect(midtop=((width-menu_space)//2+menu_space, 100 + scroll))
screen.blit(text_surf, rect)
text_surf = font40.render('I appreciate ideas, feedback, and support!', True, (0,0,0))
rect = text_surf.get_rect(midtop=((width-menu_space)//2+menu_space, 150 + scroll))
screen.blit(text_surf, rect)
do_tabs(screen, menu_space)
p.display.update()
if keys[K_F9]:
p.display.set_caption('VillageWars ' + __main__.__version__ + ' - FPS: ' + str(round(clock.get_fps(), 1)))
else:
p.display.set_caption('VillageWars ' + __main__.__version__)
clock.tick(60)
return t.getMyIP(), 5555, 'sign in'
class Credit():
space = 0
def __init__(self, text, creds, y=0, font=None, rjust=False, color=(255,255,255)):
self.y = type(self).space
type(self).space += y
self.surf = font.render(text, True, color)
self.credits = creds
self.rjust = rjust
def update(self, screen, keys=0):
global menu_space
if not (keys[K_PAGEDOWN] or keys[K_DOWN]):
self.y -= 0.6
else:
self.y -= 3
if self.rjust:
self.rect = self.surf.get_rect(topleft=((1000-menu_space)/2+menu_space-360, self.y))
else:
self.rect = self.surf.get_rect(midtop=((1000-menu_space)/2+menu_space, self.y))
self.surf.set_alpha(min([((650-self.rect.y)/650*255), 255]))
screen.blit(self.surf, self.rect)
if self.y < -200:
self.credits.remove(self)
def do_tabs(screen, width=1000, height=650):
global mouse, click, keys, open_menu_surf, open_menu_hover_surf, options, tab, menu_space, font40, creds, scroll, carry_to
menu_surf = p.Surface((menu_space, height))
menu_surf.fill((50,0,50))
screen.blit(menu_surf, (0,0))
if menu_space == 30:
rect = open_menu_surf.get_rect(topleft=(4,4))
else:
rect = open_menu_surf.get_rect(midtop=(100,4))
if rect.collidepoint(mouse):
screen.blit(open_menu_hover_surf, rect)
if click[0]:
if menu_space == 30:
menu_space = 200
else:
menu_space = 30
else:
screen.blit(open_menu_surf, rect)
if menu_space == 200:
x = 10
y = 85
for option in options:
rect_surf = p.Surface((200, 100)) # rectangle around text in menu
rect = rect_surf.get_rect(topleft=(0, y-35))
if rect.collidepoint(mouse):
rect_surf.fill((200,50,200))
screen.blit(rect_surf, rect)
surf = font40.render(option, True, (255,255,255)) # text surf
if click[0]:
tab = option
menu_space = 30
scroll = 0
carry_to = True
if tab == 'Credits':
creds = []
else:
surf = font40.render(option, True, (255,255,180)) # text surf
rect = surf.get_rect(midtop=(100, y))
screen.blit(surf, rect)
y += 100
def submitLogIn(username, password):
u = []
if len(username) == 0:
u.append('username')
if len(password) == 0:
u.append('password')
if len(u) == 0:
return {'create':False, 'username':username, 'password':password}
return u
def runLogIn(screen, clock):
global font40, font30
logInPopup = p.image.load('../assets/title page/log in popup.png')
darker = p.image.load('../assets/paused.png')
for i in range(2):
screen.blit(darker, (0,0))
username_typer = Typing(block=['@', '/', '.'])
password_typer = Typing(block=[])
typingOn = None
fontUnderline = p.font.SysFont('default', 35, italic=True)
logIn_surf = p.Surface((240, 50))
logIn_surf.fill((0,141,15))
logIn_surf_hov = p.Surface((240, 50))
logIn_surf_hov.fill((10,10,255))
logIn_surf_down = p.Surface((240, 50))
logIn_surf_down.fill((60,60,255))
rect = logIn_surf.get_rect(topleft=(0,0))
text_surf = font40.render('Log In!', True, (255,150,150))
rect = text_surf.get_rect(center=rect.center)
logIn_surf_hov.blit(text_surf, rect)
logIn_surf_down.blit(text_surf, rect)
text_surf = font40.render('Log In!', True, (0,0,0))
rect = text_surf.get_rect(center=rect.center)
logIn_surf.blit(text_surf, rect)
logIn_button = t.Button.from_surf(screen, logIn_surf, logIn_surf_hov, logIn_surf_down, midtop=((1000-menu_space)//2+menu_space, 400))
u_prob = False
p_prob = False
while True:
for event in pygame.event.get():
if event.type == QUIT:
p.quit()
sys.exit()
if event.type == KEYUP and event.key == K_ESCAPE:
return 'Cancel'
elif event.type == KEYUP:
if typingOn:
typingOn.type(event)
if event.type in (KEYUP, KEYDOWN) and event.key in (K_RSHIFT, K_LSHIFT):
username_typer.shift()
password_typer.shift()
if event.type in (KEYUP, KEYDOWN) and event.key in (K_RCTRL, K_LCTRL):
username_typer.ctrl()
password_typer.ctrl()
if event.type == KEYUP and event.key == (K_TAB):
if typingOn is None:
typingOn = username_typer
if typingOn == username_typer:
typingOn = password_typer
else:
typingOn = username_typer
if event.type == KEYUP and event.key == K_RETURN:
if typingOn == username_typer:
typingOn = password_typer
elif typingOn == password_typer:
result = submitLogIn(username_typer.result, password_typer.result)
if type(result) == dict:
return result
if 'username' in result:
u_prob = True
if 'password' in result:
p_prob = True
if logIn_button.handle_event(event):
result = submitLogIn(username_typer.result, password_typer.result)
if type(result) == dict:
return result
elif 'username' in result:
u_prob = True
if 'password' in result:
p_prob = True
mouse = p.mouse.get_pos()
click = p.mouse.get_pressed()
keys = p.key.get_pressed()
width, height = screen.get_width(), screen.get_height()
logInRect = logInPopup.get_rect(center=((1000-menu_space)//2+menu_space, height // 2))
screen.blit(logInPopup, logInRect)
username_rect = p.Surface((320, 50)).get_rect(topleft=((1000-menu_space)//2+menu_space-160, 150))
if username_rect.collidepoint(mouse) and typingOn != username_typer:
surf = p.Surface((320, 50))
surf.fill((100,100,255))
surf.set_alpha(50)
screen.blit(surf, username_rect)
if click[0]:
typingOn = username_typer
password_rect = p.Surface((320, 50)).get_rect(topleft=((1000-menu_space)//2+menu_space-160, 300))
if password_rect.collidepoint(mouse) and typingOn != password_typer:
surf = p.Surface((320, 50))
surf.fill((100,100,255))
surf.set_alpha(50)
screen.blit(surf, password_rect)
if click[0]:
typingOn = password_typer
if typingOn == username_typer:
username_surf = font40.render(username_typer.text(), True, (0,0,0))
rect = username_surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 160))
elif typingOn != username_typer:
if username_typer.text() in ('|','') and u_prob:
username_surf = font40.render('Fill this out first.', True, (250,0,0))
else:
username_surf = font40.render(username_typer.result, True, (0,0,0))
rect = username_surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 160))
if rect.right > (1000-menu_space)//2+menu_space+160:
username_typer.typing = username_typer.typing[:-2] + username_typer.character
try:
screen.blit(username_surf, rect)
except:
pass
surf = font40.render('Enter your username:', True, (255,255,255))
rect = surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 110))
screen.blit(surf, rect)
surf = font40.render('Enter your password:', True, (255,255,255))
rect = surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 260))
screen.blit(surf, rect)
if typingOn == password_typer:
if password_typer.text().endswith('|'):
password_surf = font40.render(len(password_typer.result) * '*' + '|', True, (0,0,0))
else:
password_surf = font40.render(len(password_typer.result) * '*', True, (0,0,0))
rect = password_surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 310))
elif typingOn != password_typer:
if password_typer.result in ('|', '') and p_prob:
password_surf = font40.render('Fill this out first.', True, (250,0,0))
else:
password_surf = font40.render(len(password_typer.result) * '|', True, (0,0,0))
rect = password_surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 310))
if rect.right > (1000-menu_space)//2+menu_space+160:
password_typer.typing = password_typer.typing[:-2] + password_typer.character
try:
screen.blit(password_surf, rect)
except:
pass
logIn_button.draw()
#rect = p.Surface((240, 50)).get_rect(midtop=((1000-menu_space)//2+menu_space, 400))
#if rect.collidepoint(mouse):
# surf = p.Surface((240,50))
# surf.fill((10,10,255))
# screen.blit(surf, rect)
# text_surf = font40.render('Log In!', True, (255,150,150))
# rect = text_surf.get_rect(center=rect.center)
# screen.blit(text_surf, rect)
# if click[0]:
# result = submitLogIn(username_typer.result, password_typer.result)
# if type(result) == dict:
# return result
# elif 'username' in result:
# u_prob = True
# if 'password' in result:
# p_prob = True
#else:
# text_surf = font40.render('Log In!', True, (0,0,0))
# rect = text_surf.get_rect(center=rect.center)
# screen.blit(text_surf, rect)
slump_rect = p.Surface((300, 80)).get_rect(midbottom=((1000-menu_space)//2+menu_space, 580))
if slump_rect.collidepoint(mouse):
text_surf = fontUnderline.render("Don't have an account?", True, (128,128,255))
rect = text_surf.get_rect(midbottom=((1000-menu_space)//2+menu_space, 540))
screen.blit(text_surf, rect)
text_surf = fontUnderline.render("Create one here!", True, (128,128,255))
rect = text_surf.get_rect(midbottom=((1000-menu_space)//2+menu_space, 580))
screen.blit(text_surf, rect)
if click[0]:
return runCreateAccount(screen, clock)
else:
text_surf = fontUnderline.render("Don't have an account?", True, (0,0,255))
rect = text_surf.get_rect(midbottom=((1000-menu_space)//2+menu_space, 540))
screen.blit(text_surf, rect)
text_surf = fontUnderline.render("Create one here!", True, (0,0,255))
rect = text_surf.get_rect(midbottom=((1000-menu_space)//2+menu_space, 580))
screen.blit(text_surf, rect)
p.display.update()
if keys[K_F9]:
p.display.set_caption('VillageWars ' + __main__.__version__ + ' - FPS: ' + str(round(clock.get_fps(), 1)))
else:
p.display.set_caption('VillageWars ' + __main__.__version__)
clock.tick(60)
def runCreateAccount(screen, clock):
global font40, font30
logInPopup = p.image.load('../assets/title page/create account popup.png')
#darker = p.image.load('../assets/paused.png')
#for i in range(2):
# screen.blit(darker, (0,0))
username_typer = Typing(block=['@', '/', '.', ' '])
password_typer = Typing(block=[])
cpassword_typer = Typing(block=[])
name_typer = Typing(block=['@', '/'])
email_typer = Typing(block=['/', ' '])
u_prob = False
p_prob = False
c_prob = False
n_prob = False
match_prob = False
typingOn = None
fontUnderline = p.font.SysFont('default', 35, italic=True)
surf = p.Surface((242, 57))
surf.fill((10,10,255))
surf_hov = p.Surface((242, 57))
surf_hov.fill((50,50,255))
surf_down = p.Surface((242, 57))
surf_down.fill((80,80,255))
rect = surf.get_rect(topleft=(0,0))
text_surf = font40.render('Create Account!', True, (255,150,150))
rect = text_surf.get_rect(center=rect.center)
surf_hov.blit(text_surf, rect)
surf_down.blit(text_surf, rect)
text_surf = font40.render('Create Account!', True, (0,0,0))
rect = text_surf.get_rect(center=rect.center)
surf.blit(text_surf, rect)
create_button = t.Button.from_surf(screen, surf, surf_hov, surf_down, midtop=((1000-menu_space)//2+menu_space, 543))
while True:
for event in pygame.event.get():
if event.type == QUIT:
p.quit()
sys.exit()
if event.type == KEYUP and event.key == K_ESCAPE:
return 'Cancel'
elif event.type == KEYUP:
if typingOn:
typingOn.type(event)
if event.type in (KEYUP, KEYDOWN) and event.key in (K_RSHIFT, K_LSHIFT):
username_typer.shift()
password_typer.shift()
cpassword_typer.shift()
name_typer.shift()
email_typer.shift()
if event.type in (KEYUP, KEYDOWN) and event.key in (K_RCTRL, K_LCTRL):
username_typer.ctrl()
password_typer.ctrl()
cpassword_typer.ctrl()
name_typer.ctrl()
email_typer.ctrl()
if event.type == KEYUP and event.key == (K_TAB):
if typingOn is None:
typingOn = username_typer
if typingOn == username_typer:
typingOn = password_typer
elif typingOn == password_typer:
typingOn = cpassword_typer
elif typingOn == cpassword_typer:
typingOn = name_typer
elif typingOn == name_typer:
typingOn = email_typer
elif typingOn == email_typer:
typingOn = username_typer
if event.type == KEYUP and event.key == K_RETURN:
if typingOn == username_typer:
typingOn = password_typer
elif typingOn == password_typer:
typingOn = cpassword_typer
elif typingOn == cpassword_typer:
typingOn = name_typer
elif typingOn == name_typer:
typingOn = email_typer
else:
result = submitCreate(username_typer.result, password_typer.result, cpassword_typer.result, name_typer.result, email=email_typer.result)
if type(result) == dict:
return result
elif 'username' in result:
u_prob = True
if 'password' in result:
p_prob = True
if 'cpassword' in result:
c_prob = True
if 'name' in result:
n_prob = True
match_prob = 'match' in result
if match_prob:
password_typer = Typing(block=[])
cpassword_typer = Typing(block=[])
p_prob = False
c_prob = False
if create_button.handle_event(event):
result = submitCreate(username_typer.result, password_typer.result, cpassword_typer.result, name_typer.result, email=email_typer.result)
if type(result) == dict:
return result
elif 'username' in result:
u_prob = True
if 'password' in result:
p_prob = True
if 'cpassword' in result:
c_prob = True
if 'name' in result:
n_prob = True
match_prob = 'match' in result
if match_prob:
password_typer = Typing(block=[])
cpassword_typer = Typing(block=[])
p_prob = False
c_prob = False
mouse = p.mouse.get_pos()
click = p.mouse.get_pressed()
keys = p.key.get_pressed()
width, height = screen.get_width(), screen.get_height()
logInRect = logInPopup.get_rect(center=((1000-menu_space)//2+menu_space, height // 2))
screen.blit(logInPopup, logInRect)
# Show the box for the inputs, and change active input if needed
username_rect = p.Surface((320, 50)).get_rect(topleft=((1000-menu_space)//2+menu_space-160, 60))
surf = p.Surface((320, 50))
surf.fill((255,255,255))
screen.blit(surf, username_rect)
if username_rect.collidepoint(mouse) and typingOn != username_typer:
surf = p.Surface((320, 50))
surf.fill((100,100,255))
surf.set_alpha(50)
screen.blit(surf, username_rect)
if click[0]:
typingOn = username_typer
password_rect = p.Surface((320, 50)).get_rect(topleft=((1000-menu_space)//2+menu_space-160, 160))
surf = p.Surface((320, 50))
surf.fill((255,255,255))
screen.blit(surf, password_rect)
if password_rect.collidepoint(mouse) and typingOn != password_typer:
surf = p.Surface((320, 50))
surf.fill((100,100,255))
surf.set_alpha(50)
screen.blit(surf, password_rect)
if click[0]:
typingOn = password_typer
cpassword_rect = p.Surface((320, 50)).get_rect(topleft=((1000-menu_space)//2+menu_space-160, 260))
surf = p.Surface((320, 50))
surf.fill((255,255,255))
screen.blit(surf, cpassword_rect)
if cpassword_rect.collidepoint(mouse) and typingOn != cpassword_typer:
surf = p.Surface((320, 50))
surf.fill((100,100,255))
surf.set_alpha(50)
screen.blit(surf, cpassword_rect)
if click[0]:
typingOn = cpassword_typer
name_rect = p.Surface((320, 50)).get_rect(topleft=((1000-menu_space)//2+menu_space-160, 360))
surf = p.Surface((320, 50))
surf.fill((255,255,255))
screen.blit(surf, name_rect)
if name_rect.collidepoint(mouse) and typingOn != name_typer:
surf = p.Surface((320, 50))
surf.fill((100,100,255))
surf.set_alpha(50)
screen.blit(surf, name_rect)
if click[0]:
typingOn = name_typer
email_rect = p.Surface((320, 50)).get_rect(topleft=((1000-menu_space)//2+menu_space-160, 460))
surf = p.Surface((320, 50))
surf.fill((255,255,255))
screen.blit(surf, email_rect)
if email_rect.collidepoint(mouse) and typingOn != email_typer:
surf = p.Surface((320, 50))
surf.fill((100,100,255))
surf.set_alpha(50)
screen.blit(surf, email_rect)
if click[0]:
typingOn = email_typer
# Write username input on the screen
if typingOn == username_typer:
username_surf = font40.render(username_typer.text(), True, (0,0,0))
rect = username_surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 70))
elif typingOn != username_typer:
if username_typer.text() in ('|','') and u_prob:
username_surf = font40.render('Fill this out first.', True, (250,0,0))
else:
username_surf = font40.render(username_typer.result, True, (0,0,0))
rect = username_surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 70))
if rect.right > (1000-menu_space)//2+menu_space+160:
username_typer.typing = username_typer.typing[:-2] + username_typer.character
try:
screen.blit(username_surf, rect)
except:
pass
# Write password input on the screen
if typingOn == password_typer:
if password_typer.text().endswith('|'):
password_surf = font40.render(len(password_typer.result) * '*' + '|', True, (0,0,0))
else:
password_surf = font40.render(len(password_typer.result) * '*', True, (0,0,0))
rect = password_surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 170))
elif typingOn != password_typer:
if password_typer.text() in ('|','') and p_prob:
password_surf = font40.render('Fill this out first.', True, (250,0,0))
else:
password_surf = font40.render(len(password_typer.result) * '*', True, (0,0,0))
rect = password_surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 170))
if rect.right > (1000-menu_space)//2+menu_space+160:
password_typer.typing = password_typer.typing[:-2] + password_typer.character
try:
screen.blit(password_surf, rect)
except:
pass
# Write cpassword input on the screen
if typingOn == cpassword_typer:
if password_typer.text().endswith('|'):
cpassword_surf = font40.render(len(cpassword_typer.result) * '*' + '|', True, (0,0,0))
else:
cpassword_surf = font40.render(len(cpassword_typer.result) * '*', True, (0,0,0))
rect = cpassword_surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 270))
elif typingOn != cpassword_typer:
if cpassword_typer.text() in ('|','') and c_prob:
cpassword_surf = font40.render('Fill this out first.', True, (250,0,0))
elif cpassword_typer.text() in ('|','') and match_prob:
cpassword_surf = font30.render('Passwords must match.', True, (250,0,0))
else:
cpassword_surf = font40.render(len(cpassword_typer.result) * '*', True, (0,0,0))
rect = cpassword_surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 270))
if rect.right > (1000-menu_space)//2+menu_space+160:
cpassword_typer.typing = cpassword_typer.typing[:-2] + cpassword_typer.character
try:
screen.blit(cpassword_surf, rect)
except:
pass
# Write name input on the screen
if typingOn == name_typer:
name_surf = font40.render(name_typer.text(), True, (0,0,0))
rect = cpassword_surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 370))
elif typingOn != name_typer:
if name_typer.text() in ('|','') and n_prob:
name_surf = font40.render('Fill this out first.', True, (250,0,0))
else:
name_surf = font40.render(name_typer.result, True, (0,0,0))
rect = name_surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 370))
if rect.right > (1000-menu_space)//2+menu_space+160:
name_typer.typing = name_typer.typing[:-2] + name_typer.character
try:
screen.blit(name_surf, rect)
except:
pass
# Write email input on the screen
if typingOn == email_typer:
email_surf = font40.render(email_typer.text(), True, (0,0,0))
rect = email_surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 470))
elif typingOn != email_typer:
if email_typer.result != '':
email_surf = font40.render(email_typer.result, True, (0,0,0))
else:
email_surf = font40.render('Optional', True, (160,160,160))
rect = email_surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 470))
if rect.right > (1000-menu_space)//2+menu_space+160:
email_typer.typing = email_typer.typing[:-2] + email_typer.character
try:
screen.blit(email_surf, rect)
except:
pass
surf = font40.render('Create your username:', True, (255,255,255))
rect = surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 25))
screen.blit(surf, rect)
surf = font40.render('Enter your password:', True, (255,255,255))
rect = surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 125))
screen.blit(surf, rect)
surf = font40.render('Confirm your password:', True, (255,255,255))
rect = surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 225))
screen.blit(surf, rect)
surf = font40.render('Enter your name:', True, (255,255,255))
rect = surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 325))
screen.blit(surf, rect)
surf = font40.render('Enter your email address:', True, (255,255,255))
rect = surf.get_rect(topleft=((1000-menu_space)//2+menu_space-160, 425))
screen.blit(surf, rect)
create_button.draw()
#rect = p.Surface((242, 57)).get_rect(midtop=((1000-menu_space)//2+menu_space, 543))
#if rect.collidepoint(mouse):
# surf = p.Surface((242, 57))
# surf.fill((50,50,255))
# screen.blit(surf, rect)
# text_surf = font40.render('Create Account!', True, (255,150,150))
# rect = text_surf.get_rect(center=rect.center)
# screen.blit(text_surf, rect)
# if click[0]:
# result = submitCreate(username_typer.result, password_typer.result, cpassword_typer.result, name_typer.result, email=email_typer.result)
# if type(result) == dict:
# return result
# elif 'username' in result:
# u_prob = True
# if 'password' in result:
# p_prob = True
# if 'cpassword' in result:
# c_prob = True
# if 'name' in result:
# n_prob = True
# match_prob = 'match' in result
# if match_prob:
# password_typer = Typing(block=[])
# cpassword_typer = Typing(block=[])
# p_prob = False
# c_prob = False
# p.mouse.set_pos(mouse[0], 540)
#else:
# surf = p.Surface((242, 57))
# surf.fill((10,10,255))
# screen.blit(surf, rect)
# text_surf = font40.render('Create Account!', True, (0,0,0))
# rect = text_surf.get_rect(center=rect.center)
# screen.blit(text_surf, rect)
p.display.update()
if keys[K_F9]:
p.display.set_caption('VillageWars ' + __main__.__version__ + ' - FPS: ' + str(round(clock.get_fps(), 1)))
else:
p.display.set_caption('VillageWars ' + __main__.__version__)
clock.tick(60)
def submitCreate(username, password, cpassword, name, email=None):
u = []
if len(username) == 0:
u.append('username')
if len(password) == 0:
u.append('password')
if len(cpassword) == 0:
u.append('cpassword')
if password != cpassword:
u.append('match')
if len(name) == 0:
u.append('name')
if len(u) == 0:
if not email:
email = None
return {'create':True, 'username':username, 'password':password, 'name':name, 'email':email}
return u
net2web
The net2web module (developed by Aaron McCormick) contains code for making an easy websocket server-client connection handler for games.
__init__.py
from .server import Server, Channel
from .client import Client
from .toolbox import getmyip, Clock
client.py
import websockets
import asyncio
import json
import secrets
import os
import signal
import threading
import sys
import socket
import time
import logging as log
from .toolbox import Clock
class BaseClient:
def __init__(self, host=None, port=None):
if host:
self.host = host
else:
self.host = 'water-warzone-0fc31e47a670.herokuapp.com',
if port:
self.port = port
else:
self.port = 5555
self.websocket = None
self.messages = []
self.to_send = []
self.clock = Clock(30)
def start(self):
asyncio.run(self.main())
async def send_messages(self):
while True:
try:
messages_to_send = self.to_send[:]
if len(messages_to_send) == 0:
await asyncio.sleep(self.clock.get_tick())
continue
self.to_send = []
compilation = {'messages':[]}
for message in messages_to_send:
compilation['messages'].append(message)
self.to_send = []
await self.send(compilation)
if len(compilation['messages']) > 0:
log.debug('Sent %s messages' % len(compilation))
except (websockets.exceptions.ConnectionClosedError, websockets.ConnectionClosedOK):
break
async def send(self, data):
"""
Send a message.
"""
await self.websocket.send(json.dumps(data))
async def recv(self):
while True:
try:
message = await self.websocket.recv()
messages = json.loads(message)
for event in messages['messages']:
self.messages.append(event)
except (websockets.exceptions.ConnectionClosedError, websockets.ConnectionClosedOK):
log.error('Connection Closed from server-side')
self.messages.append({'action':'disconnected'})
break
async def main(self):
try:
ip = socket.gethostbyname(self.host)
if ip.startswith('192.168.') or ip.startswith('10.') or ip.startswith('172.') or ip.startswith('127.0.0.1'):
URI = 'ws://' + self.host + ':' + str(self.port) + '/'
else:
URI = 'wss://' + self.host + '/'
except socket.error:
URI = 'ws://' + self.host + '/'
log.info('Connecting to ' + URI + '...')
async with websockets.connect(URI) as websocket:
self.websocket = websocket
self.to_send.append({'action':'connection'})
log.debug('Sending initial message')
task1 = asyncio.create_task(self.recv())
task2 = asyncio.create_task(self.send_messages())
# Wait for tasks to complete
await asyncio.gather(task1, task2)
async def error(self, message):
"""
Send an error message.
"""
event = {
"action": "error",
"message": message,
}
self.to_send.append(json.dumps(event))
async def response(self, message):
"""
Send an error message.
"""
event = {
"action": "confirm",
"message": message,
}
self.to_send.append(json.dumps(event))
class Client:
def __init__(self, host=None, port=None):
self.async_client = BaseClient(host=host, port=port)
self.async_client.thread = threading.Thread(target=self.async_client.start)
self.async_client.thread.setDaemon(True)
self.async_client.thread.start()
self._connected = False
@property
def connected(self):
return self._connected
def pump(self):
num = 0 # There's a small chance we will receive a new message during the pump
while len(self.async_client.messages):
message = self.async_client.messages.pop(0)
num += 1
if message['action'] == 'connected':
self._connected = True
if message['action'] == 'disconnected':
self.Network_disconnected(message)
log.info('Disconnection.')
sys.exit()
if hasattr(self, 'Network_' + message['action']):
getattr(self, 'Network_' + message['action'])(message) # Calls the Network function to handle an action. `message` will hold the data.
log.debug('Calling Network_' + message['action'])
else:
log.warning('No Network_' + message['action'] + ' found.')
if num > 0:
log.debug('Pumped %s messages successfully' % num)
return
Pump = pump # Compatibility with PodSixNet
def error(self, message):
self.async_client.error(message)
def send(self, data, force=False):
if self.connected or force:
self.async_client.to_send.append(data)
else:
log.debug('Not yet connected, failed to send action "' + data['action'] + '"')
Send = send # Compatible with PodSixNet
def Network_error(self, data):
log.error('Error:', data['message'])
def Network_connected(self, data):
log.info('Connected!')
def Network_disconnected(self, data):
pass
server.py
import websockets
import asyncio
import json
import secrets
import os
import signal
import threading
import secrets
import time
import logging as log
from .toolbox import Clock
class BaseChannel:
def __init__(self, host=None, port=None):
self.websocket = None
self.messages = []
self.to_send = []
self.id = secrets.token_hex()
self.clock = Clock(30)
async def send(self, data):
"""
Send a message.
"""
await self.websocket.send(json.dumps(data))
async def send_messages(self):
while True:
try:
messages_to_send = self.to_send[:]
if len(messages_to_send) == 0:
await asyncio.sleep(self.clock.get_tick())
continue
self.to_send = []
compilation = {'messages':[]}
for message in messages_to_send:
compilation['messages'].append(message)
await self.send(compilation)
if len(compilation['messages']) > 0:
log.debug('Sent %s messages' % len(compilation))
except (websockets.exceptions.ConnectionClosedError, websockets.ConnectionClosedOK):
break
async def recv(self):
while True:
try:
message = await self.websocket.recv()
messages = json.loads(message)
for event in messages['messages']:
self.messages.append(event)
except (websockets.exceptions.ConnectionClosedError, websockets.ConnectionClosedOK):
log.info('Connection Closed from client-side')
self.messages.append({'action':'disconnected'})
break
async def handler(self, websocket):
"""
Handle a connection and dispatch it according to who is connecting.
"""
self.websocket = websocket
task1 = asyncio.create_task(self.recv())
task2 = asyncio.create_task(self.send_messages())
# Wait for tasks to complete
await asyncio.gather(task1, task2)
def error(self, message):
"""
Send an error message.
"""
event = {
"action": "error",
"message": message,
}
self.to_send.append(json.dumps(event))
async def response(self, message):
"""
Send an error message.
"""
event = {
"action": "confirm",
"message": message,
}
await self.websocket.send(json.dumps(event))
class Channel:
def __init__(self, server):
self.server = server
self.async_server = BaseChannel()
self._connected = False
self._warned = []
@property
def connected(self):
return self._connected
def pump(self):
num = 0 # There's a small chance we will receive a new message during the pump
while len(self.async_server.messages):
message = self.async_server.messages.pop(0)
num += 1
if message['action'] == 'connection':
self._connected = True
self.send({'action':'connected'})
self.server.connection(self)
if message['action'] == 'disconnected':
self._connected = False
self.server.players.remove(self)
self.server.disconnection(self)
if hasattr(self, 'Network_' + message['action']):
getattr(self, 'Network_' + message['action'])(message) # Calls the `Network_<action>` function to handle an action. `message` will hold the data.
log.debug('Calling Network_' + message['action'])
else:
log.warning('No Network_' + message['action'] + ' found.')
if num > 0:
log.debug('Pumped %s messages successfully' % num)
return
def error(self, message):
self.async_server.error(message)
def send(self, data, force=False):
if self.connected or force:
self.async_server.to_send.append(data)
else:
log.debug('Not yet connected, failed to send action "' + data['action'] + '"')
Send = send # Compatibility with PodSixNet
def Network_error(self, data):
log.error('Error:', data['message'])
def Network_connection(self, data):
pass
def Network_disconnected(self, data):
pass
def __hash__(self):
return hash(self.async_client.id)
class BaseServer:
def __init__(self, server, host=None, port=None):
self.server = server
if host:
self.host = host
else:
self.host = 'water-warzone-0fc31e47a670.herokuapp.com',
if port:
self.port = port
else:
self.port = os.environ.get("PORT", "5555")
self.channels = []
def start(self):
asyncio.run(self.main())
async def main(self):
# Set the stop condition when receiving SIGTERM.
loop = asyncio.get_running_loop()
stop = loop.create_future()
try:
loop.add_signal_handler(signal.SIGTERM, stop.set_result, None)
except:
log.warning('No SIGTERM')
async with websockets.serve(self.handler, "", self.port):
await stop
async def handler(self, websocket):
"""
Handle a connection and dispatch it according to who is connecting.
"""
try:
new_channel = self.server.ChannelClass(self.server)
self.channels.append(new_channel)
await new_channel.async_server.handler(websocket)
except websockets.exceptions.InvalidHandshake as e:
error_message = "Failed to open a WebSocket connection: invalid Connection header: close."
# Customize the error message or perform any other desired actions
# ...
# Send the error message back to the client if needed
await websocket.send(error_message)
class Server():
def __init__(self, host=None, port=None):
self.async_server = BaseServer(self, host=host, port=port)
self.async_server.thread = threading.Thread(target=self.async_server.start)
self.async_server.thread.setDaemon(True)
self.async_server.thread.start()
if not hasattr(self, 'ChannelClass'):
self.ChannelClass = Channel
@property
def players(self):
return self.async_server.channels
def pump(self):
for player in self.players:
player.pump()
Pump = pump # Compatibility with PodSixNet
def connection(self, channel):
log.info('Channel connected!')
def disconnection(self, channel):
log.info('Channel disconnected')
toolbox.py
import time
import socket
import requests
class Clock:
def __init__(self, fps=30):
self.frame_delay = 1 / fps
self.start_time = time.time()
self.fps = fps
def __call__(self, fps=None):
if fps and fps != self.fps:
self.frame_delay = 1 / fps
self.fps = fps
time.sleep(self.get_tick()) # Delay for the remaining time
def get_tick(self):
end_time = time.time()
frame_time = end_time - self.start_time
self.start_time = end_time
if frame_time < self.frame_delay:
return self.frame_delay - frame_time
return 0
def getmyip(local=True):
"""
Finds the IP address of the local computer
"""
if local:
return socket.gethostbyname(socket.gethostname())
else:
url = 'https://api.ipify.org?format=json'
res = requests.get(url)
res.raise_for_status()
data = res.json()
return data['ip']
NPC.py
import pygame
import random as r
import toolbox as t
from balloon import Arrow
from animations import *
class Farmer(pygame.sprite.Sprite):
def __init__(self, building):
try:
pygame.sprite.Sprite.__init__(self, self.gp)
except:
pass
self.building = building
self.x, self.y = building.rect.x, building.rect.y
self.setout()
self.speed = 2
self.obs = []
self.food = 0
self.rect = None
@property
def innerrect(self):
return self.rect
def setout(self):
self.status = 'Going to Farms'
sm_dist = 8000
x = y = 0
for farm in self.building.server.resources:
if farm.__class__.__name__ == 'Farm':
dx, dy = r.randint(farm.x + 90, farm.x + 310), farm.y + 50
dist = t.getDist(self.x, self.y, dx, dy)
if dist < sm_dist:
sm_dist = dist
x, y = dx, dy
self.farm = farm
self.dest_x = x
self.dest_y = y
self.angle = t.getAngle(self.x, self.y, x, y)
def start_gather(self):
self.status = 'Gathering Food'
sm_dist = 1000
for food in self.farm.foods:
if food.image == 'good':
dist = t.getDist(self.x, self.y, food.x, food.y)
if dist < sm_dist:
sm_dist = dist
self.the_food = food
self.dest_x = food.x
self.dest_y = food.y
def mine(self):
try:
self.the_food.mine(self)
if self.the_food.image == 'used':
self.start_gather()
except:
self.start_gather()
def at_dest(self):
return t.getDist(self.x, self.y, self.dest_x, self.dest_y) < 10
def go_back(self):
self.status = 'Returning to Guild'
self.dest_x, self.dest_y = self.building.rect.center
def update(self):
self.obs = self.building.server.obs
self.angle = t.getAngle(self.x, self.y, self.dest_x, self.dest_y)
x, y = t.getDir(self.angle, self.speed)
lx, ly = self.x, self.y
if self.status != 'Gathering Food':
self.x += x
self.rect = pygame.Rect(self.x, self.y, 50, 50)
for ob in self.obs:
if self.rect.colliderect(ob.innerrect) and (ob.__class__.__name__ != 'Gate' or ob.owner.channel != self.building.owner):
self.x -= x
self.y += y
self.rect = pygame.Rect(self.x, self.y, 50, 50)
for ob in self.obs:
if self.rect.colliderect(ob.innerrect) and (ob.__class__.__name__ != 'Gate' or ob.owner.channel != self.building.owner):
self.y -= y
if round(lx) == round(self.x) and round(ly) == round(self.y) and self.status != 'Gathering Food':
blocked = True
while blocked:
blocked = False
self.x += x
self.rect = pygame.Rect(self.x, self.y, 50, 50)
for ob in self.obs:
if self.rect.colliderect(ob.innerrect):
blocked = True
self.y += y
self.rect = pygame.Rect(self.x, self.y, 50, 50)
for ob in self.obs:
if self.rect.colliderect(ob.innerrect):
blocked = True
if self.status == 'Gathering Food':
if self.food < 20:
self.mine()
else:
self.go_back()
if self.at_dest():
if self.status == 'Going to Farms':
self.start_gather()
elif self.status == 'Returning to Guild':
self.food = 0
self.building.owner.character.food += 20
self.setout()
for p in self.building.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.rect.size
rect.topleft = (p.character.get_x(self.rect), p.character.get_y(self.rect))
if screen.colliderect(rect):
if self.status == 'Gathering Food':
p.to_send.append({'action':'draw_NPC',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'image':'farmer',
'status':'Gathering Food : ' + str(self.food) + '/20',
'color':self.building.owner.color,
'angle':self.angle})
else:
p.to_send.append({'action':'draw_NPC',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'image':'farmer',
'status':self.status,
'color':self.building.owner.color,
'angle':self.angle})
def explode(self, angle, knockback):
x, y = t.getDir(angle, knockback)
self.x += x
self.rect = pygame.Rect(self.x, self.y, 50, 50)
for ob in self.obs:
if self.rect.colliderect(ob.innerrect) and (ob.__class__.__name__ != 'Gate' or ob.owner.channel != self.building.owner):
self.x -= x
self.y += y
self.rect = pygame.Rect(self.x, self.y, 50, 50)
for ob in self.obs:
if self.rect.colliderect(ob.innerrect) and (ob.__class__.__name__ != 'Gate' or ob.owner.channel != self.building.owner):
self.y -= y
class Miner(pygame.sprite.Sprite):
def __init__(self, building):
try:
pygame.sprite.Sprite.__init__(self, self.gp)
except:
pass
self.building = building
self.x, self.y = building.rect.x, building.rect.y
self.setout()
self.speed = 2
self.gold = 0
self.obs = []
@property
def innerrect(self):
return self.rect
def setout(self):
self.status = 'Heading to Mines'
sm_dist = 8000
x = y = 0
for farm in self.building.server.resources:
if farm.__class__.__name__ == 'Mine':
dx, dy = farm.x+100, r.randint(farm.y + 50, farm.y + 400)
dist = t.getDist(self.x, self.y, dx, dy)
if dist < sm_dist:
sm_dist = dist
x, y = dx, dy
self.farm = farm
self.dest_x = x
self.dest_y = y
self.angle = t.getAngle(self.x, self.y, x, y)
def start_gather(self):
self.status = 'Mining'
sm_dist = 1000
for food in self.farm.golds:
if food.image == 'good':
dist = t.getDist(self.x, self.y, food.x, food.y)
if dist < sm_dist:
sm_dist = dist
self.the_food = food
self.dest_x = food.x
self.dest_y = food.y
def mine(self):
try:
self.the_food.collect(self)
if self.the_food.image == 'used':
self.start_gather()
except:
self.start_gather()
def at_dest(self):
return t.getDist(self.x, self.y, self.dest_x, self.dest_y) < 10
def go_back(self):
self.status = 'Returning to Guild'
self.dest_x, self.dest_y = self.building.rect.center
def update(self):
self.obs = self.building.server.obs
self.angle = t.getAngle(self.x, self.y, self.dest_x, self.dest_y)
x, y = t.getDir(self.angle, self.speed)
lx, ly = self.x, self.y
if self.status != 'Mining':
self.x += x
self.rect = pygame.Rect(self.x, self.y, 50, 50)
for ob in self.obs:
if self.rect.colliderect(ob.innerrect) and (ob.__class__.__name__ != 'Gate' or ob.owner.channel != self.building.owner):
self.x -= x
self.y += y
self.rect = pygame.Rect(self.x, self.y, 50, 50)
for ob in self.obs:
if self.rect.colliderect(ob.innerrect) and (ob.__class__.__name__ != 'Gate' or ob.owner.channel != self.building.owner):
self.y -= y
if round(lx) == round(self.x) and round(ly) == round(self.y) and self.status != 'Mining':
blocked = True
while blocked:
blocked = False
self.x += x
self.rect = pygame.Rect(self.x, self.y, 50, 50)
for ob in self.obs:
if self.rect.colliderect(ob.innerrect):
blocked = True
self.y += y
self.rect = pygame.Rect(self.x, self.y, 50, 50)
for ob in self.obs:
if self.rect.colliderect(ob.innerrect):
blocked = True
if self.status == 'Mining':
if self.gold < 20:
self.mine()
else:
self.go_back()
if self.at_dest():
if self.status == 'Heading to Mines':
self.start_gather()
elif self.status == 'Returning to Guild':
self.gold = 0
self.building.owner.character.gold += 20
self.setout()
for p in self.building.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.rect.size
rect.topleft = (p.character.get_x(self.rect), p.character.get_y(self.rect))
if screen.colliderect(rect):
if self.status == 'Mining':
p.to_send.append({'action':'draw_NPC',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'image':'miner',
'status':'Mining : ' + str(self.gold) + '/20',
'color':self.building.owner.color,
'angle':self.angle})
else:
p.to_send.append({'action':'draw_NPC',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'image':'miner',
'status':self.status,
'color':self.building.owner.color,
'angle':self.angle})
def explode(self, angle, knockback):
x, y = t.getDir(angle, knockback)
self.x += x
self.rect = pygame.Rect(self.x, self.y, 50, 50)
for ob in self.obs:
if self.rect.colliderect(ob.innerrect) and (ob.__class__.__name__ != 'Gate' or ob.owner.channel != self.building.owner):
self.x -= x
self.y += y
self.rect = pygame.Rect(self.x, self.y, 50, 50)
for ob in self.obs:
if self.rect.colliderect(ob.innerrect) and (ob.__class__.__name__ != 'Gate' or ob.owner.channel != self.building.owner):
self.y -= y
class ArcheryTower(pygame.sprite.Sprite):
dimensions = (360, 360)
def __init__(self, server, x, y, channel, rect):
pygame.sprite.Sprite.__init__(self, self.gp)
self.building = self
self.server = server
self.x, self.y = x, y - 100
self.owner = channel.character
self.health = 300
self.dimensions = (360, 360)
self.innerrect = rect
self.server.building_blocks.append(self.innerrect)
self.server.obs.append(self)
self.balloon_speed = 45
self.attack = 24
self.knockback = 32
self.shoot_cooldown = 60
self.state = 'alive'
self.attacking = False
def update(self):
self.lookx = self.owner.x
self.looky = self.owner.y
self.attacking = False
for npc in self.server.event.NPCs:
if t.getDist(self.x, self.y, npc.x, npc.y) < 800:
self.lookx = npc.x
self.looky = npc.y
self.attacking = True
for player in self.server.players:
if not player.pending:
if t.getDist(self.x, self.y, player.character.x, player.character.y) < 800 and player != self.owner.channel and player.character.dead == False:
self.lookx = player.character.x
self.looky = player.character.y
self.attacking = True
if self.attacking == False:
close_dist = 100000
for robot in self.server.NPCs:
if robot.__class__.__name__ == 'Robot' and robot.factory.owner != self.owner.channel and t.getDist(self.x, self.y, robot.x, robot.y) < close_dist:
self.lookx = robot.x
self.looky = robot.y
close_dist = t.getDist(self.x, self.y, robot.x, robot.y)
self.attacking = True
self.angle = t.getAngle(self.x, self.y, self.lookx, self.looky)
if self.shoot_cooldown > 0:
self.shoot_cooldown -= 1
if self.shoot_cooldown < 1 and self.attacking and self.state == 'alive':
Arrow(tower=self)
self.shoot_cooldown = 60
for p in self.server.players:
if not p.pending:
p.to_send.append({'action':'archery_tower',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'angle':self.angle,
'color':self.owner.channel.color,
'health':self.health,
'state':self.state})
def isBuilding(self):
return False
def getHurt(self, damage, attacker):
if attacker != self.owner:
self.health -= damage
if self.health < 1:
self.state = 'broken'
if attacker.__class__.__name__ == 'Character':
attacker.destroyed += 1
self.owner.channel.message = attacker.channel.username + ' has broken one of your Archery Towers.'
else:
self.owner.channel.message = attacker + ' has broken one of your Archery Towers.'
self.owner.channel.message_count = 150
self.owner.channel.message_color = (255,0,0)
self.server.obs.remove(self)
def explode(self, player):
if self.state == 'broken':
self.server.building_blocks.remove(self.innerrect)
self.kill()
else:
self.getHurt(80, player)
if self.state == 'broken':
self.server.building_blocks.remove(self.innerrect)
self.kill()
class Robot(pygame.sprite.Sprite):
def __init__(self, factory):
try:
pygame.sprite.Sprite.__init__(self, self.gp)
except:
pass
self.server = factory.server
self.factory = factory
self.player = factory.owner.character
self.angle = r.randint(0, 359)
self.x = self.factory.x
self.y = self.factory.y + 140
self.fav_dir = r.choice((5, -5))
self.angry_test = 20
self.regular_test = 2
self.angry = False
self.speed = 4
self.health = 100
self.hurt = 0
self.dead = 0
self.obs = []
self.state = 'Peaceful'
self.surf = pygame.Surface((50, 50))
self.rect = self.surf.get_rect(center=(self.x, self.y))
self.safety_zone = pygame.Surface((3400, 2190)).get_rect(center=(self.factory.x, self.factory.y))
self.range = pygame.Surface((3000, 2000)).get_rect(center=(self.factory.x, self.factory.y))
@property
def innerrect(self):
return self.rect
@property
def building(self):
return self.factory
def update(self):
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.obs:
if rect.colliderect(ob.innerrect) and (ob.__class__.__name__ != 'Gate' or ob.owner.channel != self.factory.owner):
self.getHurt(100, 0, 0)
self.obs = self.server.obs
for robot in self.server.NPCs:
if robot.__class__.__name__ == 'Robot' and robot.factory.owner != self.factory.owner:
self.obs.append(robot)
if self.hurt:
self.hurt -= 1
if self.dead:
self.dead -= 1
if not self.dead:
self.AI()
for p in self.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.rect.size
rect.topleft = (p.character.get_x(self.rect), p.character.get_y(self.rect))
if screen.colliderect(rect):
p.to_send.append({'action':'draw_robot',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'name':'Robot',
'health':self.health,
'image':('hurt' if self.hurt else 'regular'),
'color':self.factory.owner.color,
'angle':self.angle})
for p in self.server.players:
if not p.pending and self.rect.colliderect(p.character.rect) and p != self.factory.owner and p.character.dead == False:
self.getHurt(0, self.angle + 180, 50)
p.character.getHurt(10, self.factory.owner.username + "'s Robots", self.angle, 2)
def AI(self):
if not self.rect.colliderect(self.safety_zone):
self.state = 'Returning'
self.angle = t.getAngle(self.x, self.y, self.factory.x, self.factory.y + 140)
if self.state == 'Returning':
if round(self.x) == round(self.factory.x) and round(self.y) == round(self.factory.y):
self.state = 'Peaceful'
if self.state == 'Attacking':
speed = self.speed
else:
speed = 2
origx = self.x
x, y = t.getDir(self.angle, total=speed)
self.x += x
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.obs:
if rect.colliderect(ob.innerrect) and (ob.__class__.__name__ != 'Gate' or ob.owner.channel != self.factory.owner):
self.x -= x
origy = self.y
self.y += y
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.obs:
if rect.colliderect(ob.innerrect) and (ob.__class__.__name__ != 'Gate' or ob.owner.channel != self.factory.owner):
self.y -= y
for item in self.server.bushes:
if self.rect.colliderect(item.innerrect):
if item.__class__.__name__ == 'SpikyBush':
self.getHurt(1, self.angle + 180, 1.5)
else:
self.getHurt(0, self.angle + 180, 1.5)
self.rect = self.surf.get_rect(center=(self.x, self.y))
suspects = []
for p in self.server.players:
if not p.pending:
if p.character.rect.colliderect(self.range) and not p.character.dead and not p == self.factory.owner:
suspects.append(p.character)
if len(suspects) > 1:
closest = suspects[0]
for suspect in suspects[1:]:
if t.getDist(self.x, self.y, suspect.x, suspect.y) < t.getDist(self.x, self.y, closest.x, closest.y):
closest = suspect
suspect = closest
elif len(suspects) == 1:
suspect = suspects[0]
else:
suspect = None
if suspect != None:
self.state = 'Attacking'
self.attacking = suspect
self.angle = t.getAngle(self.x, self.y, self.attacking.x, self.attacking.y) + r.randint(-2,2)
def init(self):
self.x = self.factory.x
self.y = self.factory.y + 140
self.state = 'Peaceful'
self.health = 100
def getHurt(self, damage, angle, knockback):
self.health -= damage
if self.health <= 0:
Explosion(self)
self.dead = 200
for p in self.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
screen.center = p.character.rect.center
if screen.colliderect(self.rect):
p.to_send.append({'action':'sound', 'sound':'die'})
self.init()
if damage != 0:
self.hurt = 8
x, y = t.getDir(angle, knockback)
self.x += x
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.obs:
if rect.colliderect(ob.innerrect):
self.x -= x
self.y += y
rect = self.surf.get_rect(center=(self.x, self.y))
for ob in self.obs:
if rect.colliderect(ob.innerrect):
self.y -= y
def explode(self, angle, knockback):
self.getHurt(80, angle, knockback)
obstacle.py
import pygame
import toolbox as t
from animations import *
import random as r
class Obstacle(pygame.sprite.Sprite):
def __init__(self, server, x, y):
pygame.sprite.Sprite.__init__(self, self.gp)
self.server = server
self.image = None
self.dimentions = (50, 50)
self.x = x
self.y = y
self.max_health = self.health = 300
self.owner = None
def update(self):
for p in self.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.innerrect.size
rect.topleft = (p.character.get_x(self.innerrect), p.character.get_y(self.innerrect))
if screen.colliderect(rect):
p.to_send.append({'action':'draw_obstacle',
'image':self.image,
'coords':(p.character.get_x(self), p.character.get_y(self)),
'health':self.health,
'max_health':self.max_health})
def getHurt(self, damage, attacker):
if self.health > 0:
self.health -= damage
if self.health < 1:
self.server.building_blocks.remove(self.innerrect)
self.server.obs.remove(self)
self.kill()
def isBuilding(self):
return False
def explode(self):
self.getHurt(80, None)
class Tree(pygame.sprite.Sprite):
def __init__(self, server, x, y):
pygame.sprite.Sprite.__init__(self, self.gp)
self.server = server
self.image = None
self.x = x
self.y = y
self.max_health = self.health = 300
self.owner = None
self.surf = pygame.Surface((200, 280))
self.rect = self.surf.get_rect(center=(x,y))
self.innerrect = pygame.Surface((50, 120)).get_rect(midtop=self.rect.center)
server.building_blocks.append(self.innerrect)
server.obs.append(self)
def update(self):
for p in self.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.rect.size
rect.center = (p.character.get_x(self), p.character.get_y(self))
if screen.colliderect(rect):
p.to_send.append({'action':'draw_obstacle',
'image':'tree',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'health':self.health,
'max_health':self.max_health})
def getHurt(self, damage, attacker):
if self.health > 0:
self.health -= damage
if self.health < 1:
self.server.building_blocks.remove(self.innerrect)
self.server.obs.remove(self)
self.kill()
def isBuilding(self):
return False
def explode(self):
self.getHurt(160, None)
class Sappling(pygame.sprite.Sprite):
def __init__(self, server, x, y):
pygame.sprite.Sprite.__init__(self, Tree.gp)
self.server = server
self.x = x
self.count = 100 #30*60*1
self.y = y
self.max_health = self.health = 120
self.owner = None
self.surf = pygame.Surface((60, 90))
self.rect = self.surf.get_rect(center=(x,y))
server.building_blocks.append(self.rect)
def update(self):
self.count -= 1
if not self.count:
self.server.building_blocks.remove(self.rect)
Tree(self.server, self.x, self.y)
self.kill()
return
for p in self.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.rect.size
rect.center = (p.character.get_x(self), p.character.get_y(self))
if screen.colliderect(rect):
p.to_send.append({'action':'draw_obstacle',
'image':'sappling',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'health':self.health,
'max_health':self.max_health})
def getHurt(self, damage, attacker):
if self.health > 0:
self.health -= damage
if self.health < 1:
self.server.building_blocks.remove(self.innerrect)
self.server.obs.remove(self)
self.kill()
def isBuilding(self):
return False
def explode(self):
self.getHurt(120, None)
class Boulder(Obstacle):
def __init__(self, server, x, y):
Obstacle.__init__(self, server, x, y)
self.image = 'boulder'
self.max_health = self.health = r.randint(18, 32) * 10
self.p = pygame.image.load('../assets/boulder.png')
self.innerrect = self.p.get_rect(center=(x,y))
server.building_blocks.append(self.innerrect)
server.obs.append(self)
class Crate(Obstacle):
def __init__(self, player, x, y):
Obstacle.__init__(self, player.channel.server, x, y)
self.image = 'crate'
self.max_health = self.health = 800
self.p = pygame.Surface((50, 50))
self.innerrect = self.p.get_rect(center=(x,y))
self.server.building_blocks.append(self.innerrect)
self.server.obs.append(self)
self.owner = player
def explode(self):
self.server.building_blocks.remove(self.innerrect)
self.server.obs.remove(self)
self.kill()
def update(self):
for p in self.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.innerrect.size
rect.topleft = (p.character.get_x(self.innerrect), p.character.get_y(self.innerrect))
if screen.colliderect(rect):
p.to_send.append({'action':'draw_obstacle',
'image':self.image,
'coords':(p.character.get_x(self), p.character.get_y(self)),
'health':self.health,
'max_health':self.max_health})
class Barrel(Obstacle):
def __init__(self, player, x, y, angle, health=15, max_health=15, explosive=False):
Obstacle.__init__(self, player.channel.server, x, y)
self.image = 'barrel'
self.explosive = explosive
self.max_health = max_health
self.health = health
self.p = pygame.Surface((50, 50))
self.innerrect = self.p.get_rect(center=(x,y))
self.player = player
self.obs = self.player.channel.server.obs
self.angle = angle
self.speed = 16
self.sedentary = False
self.roll_angle = angle
self.damage = self.health
self.knockback = 80
if -90 <= angle <= 90:
self.roll_direction = -10
else:
self.roll_direction = 10
def explode(self):
if self.innerrect in self.server.building_blocks:
self.server.building_blocks.remove(self.innerrect)
self.server.obs.remove(self)
self.kill()
def update(self):
self.damage = self.health
if not self.sedentary:
self.roll_angle += self.roll_direction
self.move(self.angle)
for p in self.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.innerrect.size
rect.topleft = (p.character.get_x(self), p.character.get_y(self))
if screen.colliderect(rect):
p.to_send.append({'action':'draw_obstacle',
'image':self.image,
'coords':(p.character.get_x(self), p.character.get_y(self)),
'health':self.health,
'max_health':self.max_health,
'angle':self.roll_angle,
'explosive':self.explosive})
def sedent(self):
if self.explosive:
self.this_explode()
self.kill()
return
self.sedentary = True
self.server.building_blocks.append(self.innerrect)
self.server.obs.append(self)
self.getHurt(10, 'Santa Clause') # Placeholder
for p in self.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.innerrect.size
rect.topleft = (p.character.get_x(self), p.character.get_y(self))
if screen.colliderect(rect):
p.to_send.append({'action':'sound','sound':'barrel'})
def this_explode(self): # warning: self may be player object
BAM(self)
try:
self.server
except:
self.server = self.channel.server
self.innerrect = self.rect
self.player = self
for p in self.server.players:
screen = pygame.Rect(0, 0, 1000, 650)
screen.center = p.character.rect.center
if screen.colliderect(self.innerrect):
p.Send({'action':'sound', 'sound':'TNT'})
if True: # Too lazy to unindent
ray = pygame.Rect(0, 0, 350, 350)
ray.center = self.x, self.y
for item in self.server.obstacles:
if item != self and item.innerrect.colliderect(ray):
item.explode()
for item in self.server.trees:
if item != self and item.innerrect.colliderect(ray):
item.explode()
for item in self.server.buildings:
if item.innerrect.colliderect(ray):
item.getHurt(120, self.player)
elif item.rect.colliderect(ray):
item.getHurt(120, self.player)
print('Explosion')
for item in self.server.players:
print(item.username)
if item.character.rect.colliderect(ray):
print(item.username.upper())
item.character.getHurt(80, self.player, t.getAngle(self.x, self.y, item.character.x, item.character.y), 120, '<Victim> was blown up by <Attacker>')
for item in self.server.NPCs:
if item.innerrect.colliderect(ray):
if item.__class__.__name__ == 'ArcheryTower':
item.explode(self.player)
else:
item.explode(t.getAngle(self.x, self.y, item.x, item.y), 80)
for item in self.server.event.NPCs:
if item.rect.colliderect(ray):
item.explode(self.player, self)
for item in self.server.bushes:
if item.rect.colliderect(ray):
item.explode()
if self.player == self:
del self.server
del self.innerrect
del self.player
def move(self, angle):
obs = self.obs[:]
x, y = t.getDir(angle, self.speed)
self.move_x(round(x), obs)
self.move_y(round(y), obs)
for item in obs:
rect = item.innerrect if hasattr(item, 'innerrect') else item.rect
if self.innerrect.colliderect(rect):
try:
item.getHurt(self.damage, self.player)
except:
item.getHurt(self.damage, self.player, self.angle, self.knockback)
self.sedent()
return
for p in self.server.players:
if self.innerrect.colliderect(p.character.rect) and p.character != self.player:
self.sedent()
p.character.getHurt(self.damage, self.player, self.angle, self.knockback, msg='<Victim> got rolled over.')
return
for b in self.server.bushes:
if self.innerrect.colliderect(b.rect):
self.sedent()
b.getHurt(self.damage, self.player)
return
for npc in self.server.NPCs:
if npc.__class__.__name__ == 'Robot' and self.innerrect.colliderect(npc.rect):
self.sedent()
npc.getHurt(self.damage, self.angle, self.knockback)
return
if npc.__class__.__name__ == 'ArcheryTower' and self.innerrect.colliderect(npc.innerrect):
self.sedent()
npc.getHurt(self.damage, self.angle, self.knockback)
return
for npc in self.server.event.NPCs:
if self.innerrect.colliderect(npc.rect):
self.sedent()
result = npc.getHurt(self.player, self.damage, self.angle, self.knockback)
def move_x(self, a, obs):
self.innerrect.x += a
self.x, self.y = self.innerrect.center
def move_y(self, a, obs):
self.innerrect.y += a
self.x, self.y = self.innerrect.center
class Vine(Obstacle):
def __init__(self, player, x, y, direction=None, speed=r.randint(25, 110)):
Obstacle.__init__(self, player.channel.server, x, y)
self.image = 'vine'
self.max_health = self.health = speed * 2
self.p = pygame.Surface((50, 50))
self.innerrect = self.p.get_rect(center=(x,y))
self.server.building_blocks.append(self.innerrect)
self.server.obs.append(self)
self.owner = player
self.speed = speed
self.count = self.speed
dirs = [(0, 50), (50, 0), (-50, 0), (0, -50)]
if direction:
dirs.remove(direction)
self.dir = r.choice(dirs)
for v in self.server.obstacles:
if v.__class__ == Vine and self.innerrect.colliderect(v.innerrect) and v != self:
v.count = 1
v.health = v.max_health
v.dir = self.dir
v.owner = self.owner
self.explode()
def explode(self):
if self.innerrect in self.server.building_blocks:
self.server.building_blocks.remove(self.innerrect)
if self in self.server.obs:
self.server.obs.remove(self)
self.kill()
def update(self):
if self.count:
self.count -= 1
if not self.count:
Vine(self.owner, self.x + self.dir[0], self.y + self.dir[1], direction=self.dir, speed=self.speed)
for b in self.server.buildings:
if not b.owner == self.owner.channel and self.innerrect.colliderect(b.innerrect):
b.getHurt(0.02, self.owner.channel.username + '\'s invasive vine')
for p in self.server.players:
if not p.pending:
p.to_send.append({'action':'draw_obstacle',
'image':self.image,
'coords':(p.character.get_x(self), p.character.get_y(self)),
'health':self.health,
'max_health':self.max_health})
class SpikyBush(pygame.sprite.Sprite):
def __init__(self, player, x, y):
pygame.sprite.Sprite.__init__(self, self.gp)
self.server = player.channel.server
self.x = x
self.y = y
self.dimensions = (50, 50)
self.max_health = self.health = 260
self.p = pygame.Surface(self.dimensions)
self.rect = self.p.get_rect(center=(x,y))
self.server.building_blocks.append(self.innerrect)
self.owner = player
@property
def innerrect(self):
return self.rect
def explode(self):
self.server.building_blocks.remove(self.innerrect)
self.kill()
def update(self):
for p in self.server.players:
if not p.pending:
p.to_send.append({'action':'draw_obstacle',
'image':'spiky bush',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'health':self.health,
'max_health':self.max_health})
def getHurt(self, damage, attacker):
if self.health > 0:
self.health -= damage
if self.health < 1:
self.explode()
def isBuilding(self):
return False
class Gate(Obstacle):
def __init__(self, player, x, y, rot):
Obstacle.__init__(self, player.channel.server, x, y)
self.image = 'gate'
self.max_health = self.health = 1000
if rot == False:
self.p = pygame.Surface((100, 200))
else:
self.p = pygame.Surface((200, 100))
self.innerrect = self.p.get_rect(center=(x,y))
self.server.building_blocks.append(self.innerrect)
self.server.obs.append(self)
self.owner = player
self.rotated = rot
def explode(self):
self.getHurt(900, None)
def update(self):
for p in self.server.players:
if not p.pending:
p.to_send.append({'action':'draw_obstacle',
'image':self.image,
'coords':(p.character.get_x(self), p.character.get_y(self)),
'health':self.health,
'max_health':self.max_health,
'rotated?':self.rotated})
class TNT(pygame.sprite.Sprite):
def __init__(self, player, x, y):
pygame.sprite.Sprite.__init__(self, self.gp)
self.health = 130
self.x = x
self.y = y
self.p = pygame.Surface((50, 50))
self.innerrect = self.p.get_rect(center=(x,y))
self.server = player.channel.server
self.server.building_blocks.append(self.innerrect)
self.server.obs.append(self)
self.owner = player
#player.channel.achievement('You used TNT! (Watch out)')
def update(self):
self.health -= 1
if self.health == 0:
BAM(self)
for p in self.server.players:
screen = pygame.Rect(0, 0, 1000, 650)
screen.center = p.character.rect.center
if screen.colliderect(self.innerrect):
p.Send({'action':'sound', 'sound':'TNT'})
self.server.building_blocks.remove(self.innerrect)
self.server.obs.remove(self)
ray = pygame.Rect(0, 0, 400, 400)
ray.center = self.x, self.y
for item in self.server.obstacles:
if item != self and item.innerrect.colliderect(ray):
item.explode()
for item in self.server.trees:
if item != self and item.innerrect.colliderect(ray):
item.explode()
for item in self.server.buildings:
if item.innerrect.colliderect(ray):
item.getHurt(120, self.owner)
elif item.rect.colliderect(ray):
item.getHurt(120, self.owner)
for item in self.server.players:
if item.character.rect.colliderect(ray):
item.character.getHurt(80, self.owner, t.getAngle(self.x, self.y, item.character.x, item.character.y), 120, '<Victim> was blown up by <Attacker>')
for item in self.server.NPCs:
if item.innerrect.colliderect(ray):
if item.__class__.__name__ == 'ArcheryTower':
item.explode(self.owner)
else:
item.explode(t.getAngle(self.x, self.y, item.x, item.y), 80)
for item in self.server.event.NPCs:
if item.rect.colliderect(ray):
item.explode(self.owner, self)
for item in self.server.bushes:
if item.rect.colliderect(ray):
item.explode()
self.kill()
for p in self.server.players:
if not p.pending:
p.to_send.append({'action':'draw_obstacle',
'image':'TNT',
'coords':(p.character.get_x(self), p.character.get_y(self))})
def isBuilding(self):
return False
def getHurt(self, damage, attacker):
pass
def explode(self):
''' Ha! '''
pass
class Block():
def __init__(self, topleft, size):
self.innerrect = pygame.Rect(topleft[0], topleft[1], size[0], size[1])
self.owner = None
def isBuilding(self):
return False
def getHurt(self, damage, attacker):
pass
player.py
import pygame
import time
import toolbox as t
from balloon import Balloon, Bolt
from obstacle import *
from building import *
from animations import *
from NPC import ArcheryTower
import __main__
class Character():
def __init__(self, channel, x, y):
self.channel = channel
self.image = pygame.Surface((50, 50))
self.x = x
self.y = y
self.x_flip = 500-x
self.y_flip = 325-y
self.angle = 0
self.speed = self.moving = 8
self.health = self.max_health = 100
self.hurt_count = 1
self.dead = False
self.explosive = True
if self.channel.username == 'ModestNoob' or self.channel.username == 'f':
self.gold = 100000
self.food = 100000
elif __main__.GAMEMODE == 'OP':
self.gold = 1600
self.food = 1600
elif __main__.GAMEMODE == 'Immediate':
self.gold = 100
self.food = 100
elif __main__.GAMEMODE == 'Mutated':
self.gold = 45
self.food = 25
elif __main__.GAMEMODE == 'Express':
self.gold = 100
self.food = 100
else:
self.gold = 0
self.food = 0
self.strength = 0
self.obs = []
self.rect = self.image.get_rect(center=(self.x, self.y))
self.shoot_cooldown = 0
self.barbshoot_cooldown = -1
self.shot_speed = 15
self.crate_cooldown = 0
self.crate_hold = False
self.spiky_bush_hold = False
self.invincible = False
self.respawn_count = 0
self.meal = False
self.meal_type = 0
self.crates = 0
self.spiky_bushes = 0
self.spence = 'gold'
self.garden_xp = 0
self.shield_count = 0
self.shield_angle = 0
self.has_shield = False
self.barrel_health = 0
self.in_barrel = False
self.barrel_max_health = 0
### Stat Side ###
self.attack = 10
self.damage_cost = 30
self.balloon_speed = 16
self.speed_cost = 10
self.knockback = 10
self.knockback_cost = 10
self._kills = 0
self._destroyed = 0
self._deaths = 0
self._eliminations = 0
### Info Side - Statistics ( Soon to be updated ) ###
@property
def kills(self):
return self._kills
@kills.setter
def kills(self, value):
self._kills = value
@property
def destroyed(self):
return self._destroyed
@destroyed.setter
def destroyed(self, value):
self._destroyed = value
@property
def deaths(self):
return self._deaths
@deaths.setter
def deaths(self, value):
self._deaths = value
@property
def eliminations(self):
return self._eliminations
@eliminations.setter
def eliminations(self, value):
self._eliminations = value
@property
def statistics(self):
return (self.channel.username, 'kills', self.kills)
@property
def have_builder(self):
true = False
for inn in self.channel.get_buildings():
if inn.__class__.__name__ == 'Inn':
if inn.NPC.__class__.__name__ == 'Builder':
true = True
break
if inn.type == 'Builder\'s':
true = True
break
return true
def get_x(self, item):
try:
return item.x + self.x_flip
except:
return item + self.x_flip
def get_y(self, item):
try:
return item.y + self.y_flip
except:
return item + self.y_flip
def move_x(self, a, type_=None):
self.x += a
self.x_flip -= a
self.rect = self.image.get_rect(center=(self.x, self.y))
if not self.dead:
for item in self.obs:
thr = False
if item.__class__ == Gate and item.owner == self:
thr = True
if self.rect.colliderect(item.innerrect) and not thr:
self.x -= a
self.x_flip += a
def move_y(self, a, type_=None):
self.y += a
self.y_flip -= a
self.rect = self.image.get_rect(center=(self.x, self.y))
if not self.dead:
for item in self.obs:
thr = False
if item.__class__ == Gate and item.owner == self:
thr = True
if self.rect.colliderect(item.innerrect) and not thr:
self.y -= a
self.y_flip += a
for item in self.channel.server.bushes:
if self.rect.colliderect(item.innerrect) and type_ != 'hurt':
if item.__class__.__name__ == 'SpikyBush':
self.getHurt(1, 'a spiky bush', self.angle + 180, 4, msg='<Victim> fell in <Attacker>.')
else:
self.getHurt(0, '', self.angle + 180, 4)
def move(self, angle):
x, y = t.getDir(angle, self.get_speed())
self.move_x(round(x))
self.move_y(round(y))
def update(self):
if self.channel.build_to_place:
self.channel.to_send.append({'action':'preview', 'dimensions':((self.channel.build_to_place.dimensions[0]*0.8, self.channel.build_to_place.dimensions[1]*0.8) if self.have_builder else self.channel.build_to_place.dimensions), 'ArcheryTower?':self.channel.build_to_place==ArcheryTower})
self.rect = self.image.get_rect(center=(self.x, self.y))
if not self.dead:
for item in self.obs:
if item.__class__ == Crate and self.rect.colliderect(item.innerrect):
x, y = t.getDir(self.angle + 180, 40)
self.x += x
self.x_flip -= x
self.y += y
self.y_flip -= y
else:
thr = False
if item.__class__ == Gate and item.owner == self:
thr = True
if self.rect.colliderect(item.innerrect) and not thr:
self.suffocate()
if self.shoot_cooldown > 0:
self.shoot_cooldown -= 1
if self.crate_cooldown > 0:
self.crate_cooldown -= 1
if self.hurt_count > 1:
self.hurt_count -= 1
if self.shield_count:
self.shield_count -= 1
if self.barbshoot_cooldown:
self.barbshoot_cooldown -= 1
if self.respawn_count > 0:
self.respawn_count -= 1
if self.respawn_count == 0:
self.respawn()
self.obs = self.channel.server.obs
if not self.dead:
if not self.barbshoot_cooldown:
self.barbshoot()
for p in self.channel.server.players:
if not p.pending:
barrel_image = self.barrel_max_health / (self.barrel_health+1)>2
if self.explosive:
barrel_image = 'TNT'
p.to_send.append({'action':'draw_player',
'hurt':int(bool(self.hurt_count - 1)),
'coords':(p.character.get_x(self), p.character.get_y(self)),
'angle':self.angle,
'color':self.channel.color,
'username':self.channel.username,
'health':self.health,
'max_health':self.max_health,
'skin':self.channel.skin,
'shield':(self.shield_angle if self.shield_count else None),
'in_barrel':(barrel_image, self.in_barrel)})
def hud(self):
return { 'action':'hud',
'x':self.x,
'y':self.y,
'angle':self.angle,
'color':self.channel.color,
'username':self.channel.username,
'health':self.health,
'gold':self.gold,
'food':self.food,
'max_health':self.max_health,
'food?':self.meal,
'type':self.meal_type,
'crates':self.crates,
'spiky_bushes':self.spiky_bushes,
'gametime':time.time() - self.channel.server.starttime,
}
def barbshoot(self):
dire = 650
player = None
for p in self.channel.server.players:
if p.pending:
if t.getDist(self.x, self.y, p.character.x, p.character.y) < dire and p != self.channel:
player = p.character
dire = t.getDist(self.x, self.y, p.character.x, p.character.y)
if player:
self.angle = t.getAngle(self.x, self.y, player.x, player.y)
Bolt(archer=self)
self.barbshoot_cooldown = 50
def HandleInput(self, keys, mouse):
if self.barrel_health and not self.dead and not self.channel.in_window and not self.channel.in_innpc_window:
change = False
if self.in_barrel:
if not keys[pygame.K_z]:
change = True
else:
if keys[pygame.K_z]:
change = True
if change:
self.in_barrel = not self.in_barrel
for p in self.channel.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.rect.size
rect.topleft = (p.character.get_x(self), p.character.get_y(self))
if screen.colliderect(rect):
p.to_send.append({'action':'sound','sound':'barrel'})
else:
self.in_barrel = False
beg_building = self.channel.build_to_place
beg_gold = self.gold
beg_food = self.food
if not self.channel.in_window:
if not keys[pygame.K_x] and self.crate_hold:
self.crate_hold = False
if not keys[pygame.K_c] and self.spiky_bush_hold:
self.spiky_bush_hold = False
self.angle = t.getAngle(500, 325, mouse[0], mouse[1])
#if keys[pygame.K_a]:
# self.channel.achievement('You pressed the A button!')
#if keys[pygame.K_8]:
# self.channel.achievement('You pressed the 8 button!')
if keys[pygame.K_SPACE] and not self.in_barrel:
self.move(self.angle)
if keys[pygame.K_c] and not self.dead:
if self.channel.text == 'Press c to place sappling':
Sappling(self.channel.server, self.x, self.y)
self.channel.text = ''
self.spiky_bush_hold = True
elif self.spiky_bush_hold == False and self.spiky_bushes > 0:
x, y = self.x, self.y
move = t.getDir(self.angle, 80)
x += move[0]
y += move[1]
SpikyBush(self, x, y)
self.spiky_bush_hold = True
self.spiky_bushes -= 1
if keys[pygame.K_x]:
if self.channel.text == 'Press x to place gate':
self.channel.text = ''
x, y = self.x, self.y
move = t.getDir(self.angle, 100)
x += move[0]
y += move[1]
rotated = False
if 45 < self.angle < 135 or -45 > self.angle > -135:
rotated = True
Gate(self, x, y, rotated)
self.crate_hold = True
elif self.channel.text == 'Press x to place TNT':
self.channel.text = ''
x, y = self.x, self.y
move = t.getDir(self.angle, 80)
x += move[0]
y += move[1]
TNT(self, x, y)
self.crate_hold = True
elif not self.dead and self.crate_hold == False and self.crates > 0:
x, y = self.x, self.y
move = t.getDir(self.angle, 80)
x += move[0]
y += move[1]
Crate(self, x, y)
self.crate_hold = True
self.crates -= 1
if keys[pygame.K_DELETE] and self.channel.build_to_place != None:
self.channel.build_to_place = None
self.channel.text = ''
if self.spence == 'gold':
self.channel.message = 'You deleted the building, you gain 10 gold.'
self.gold += 10
else:
self.channel.message = 'You deleted the building, you gain 10 food.'
self.food += 10
self.channel.message_count = 150
self.channel.message_color = (255,100,0)
if mouse[2] and not self.dead:
not_shoot = False
if self.dead == False:
for farm in self.channel.server.resources:
if farm.HandleInput(mouse, self):
not_shoot = True
if self.in_barrel:
Barrel(self, self.x, self.y, self.angle, self.barrel_health, self.barrel_max_health, self.explosive)
self.in_barrel = False
self.barrel_health = 0
self.shoot_cooldown = self.shot_speed * 2
for p in self.channel.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.rect.size
rect.topleft = (p.character.get_x(self), p.character.get_y(self))
if screen.colliderect(rect):
p.to_send.append({'action':'sound','sound':'shot'})
return
if not not_shoot:
self.shoot()
if self.channel.in_window and mouse[2] and not self.dead and not self.channel.in_innpc_window:
not_farm = True
not_shoot = True
for option in self.channel.window['options']:
x = 200
y = 200 + option[0] * 40
rect = pygame.Rect(x, y, 600, 50)
if rect.collidepoint((mouse[0], mouse[1])):
option[1](self)
break
if self.channel.in_window and mouse[2] and not self.dead and self.channel.in_innpc_window:
for i, option in enumerate(self.channel.window['options']):
x = 200
y = 200 + i * 40
rect = pygame.Rect(x, y, 600, 50)
if rect.collidepoint((mouse[0], mouse[1])):
option[1](self.channel)
break
if mouse[4] and not self.dead:
if self.channel.build_to_place != None:
result = builder(self.channel.build_to_place, self, self.have_builder)
to_build = result[0]
if to_build:
b = self.channel.build_to_place(self.channel.server, self.x, self.y - 140, self.channel, result[1])
self.channel.text = ''
self.channel.build_to_place = None
try:
self.channel.message = 'You have placed a ' + b.type + '.'
except:
self.channel.message = 'You have placed an Archery Tower.'
self.channel.message_count = 150
self.channel.message_color = (255,205,0)
else:
self.channel.message = 'You cannot place this building here.'
self.channel.message_count = 100
self.channel.message_color = (255,0,0)
elif not self.in_barrel and not self.channel.in_window and not self.channel.in_innpc_window:
for b in self.channel.server.buildings:
rect = b.p.get_rect(center=(self.get_x(b), self.get_y(b)))
if rect.collidepoint((mouse[0], mouse[1])):
b.open_window(self.channel)
self.channel.to_send.append({'action':'sound', 'sound':'ow'})
else:
rect = b.rect.copy()
rect.x, rect.y = self.get_x(rect), self.get_y(rect)
if rect.collidepoint((mouse[0], mouse[1])):
b.open_window(self.channel)
self.channel.to_send.append({'action':'sound', 'sound':'ow'})
if b.__class__ == Inn and b.NPC != None and b.owner == self.channel:
rect = pygame.Rect(0, 0, 0, 0)
rect.topleft = self.get_x(b.NPC.rect), self.get_y(b.NPC.rect)
rect.size = b.NPC.rect.size
if rect.collidepoint((mouse[0], mouse[1])):
self.channel.in_window = True
self.channel.in_innpc_window = True
self.channel.window = b.NPC.window
self.channel.to_send.append({'action':'sound', 'sound':'ow'})
if self.channel.message == 'The Gold Discovery Rate is at its maximum!' and not [b for b in self.channel.get_buildings() if b.type == 'Miner\'s Guild']:
self.channel.message = 'Get a Miner\'s Guild first.'
if self.channel.message == 'The Food Production Rate is at its maximum!' and not [b for b in self.channel.get_buildings() if b.type == 'Farmer\'s Guild']:
self.channel.message = 'Get a Farmer\'s Guild first.'
if __main__.GAMEMODE == 'Mutated' and self.channel.build_to_place != beg_building and self.channel.build_to_place is not None:
self.channel.message = 'No buildings in Mutated Gamemode. Returning %s gold, %s food' % (beg_gold - self.gold, beg_food - self.food)
self.channel.message_color = (255,128,0)
self.channel.build_to_place = beg_building
self.gold = beg_gold
self.food = beg_food
self.channel.text = ''
def eat(self):
if not self.dead:
self.meal = False
self.health = self.max_health
self.channel.message = 'You ate your meal, your health bar is now full again.'
self.channel.message_color = (255,205,0)
def dine_in(self):
self.health = self.max_health
def getHurt(self, damage, attacker, angle, knockback, msg = '<Attacker> splashed <Victim> too hard.'):
if self.in_barrel:
if self.explosive:
self.in_barrel = False
self.barrel_health = 0
#self.explosive = False
Barrel.this_explode(self)
return 'BAM'
else:
self.barrel_health -= damage
if self.barrel_health < 0 or msg == '<Victim> was blown up by <Attacker>':
self.barrel_health = 0
self.in_barrel = False
for p in self.channel.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.rect.size
rect.topleft = (p.character.get_x(self), p.character.get_y(self))
if screen.colliderect(rect):
p.to_send.append({'action':'sound','sound':'barrel'})
return
if (randint(0, 2) == 0 and self.has_shield) or self.invincible:
self.shield_angle = angle + 180
self.shield_count = 20
for p in self.channel.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
rect = pygame.Rect(0, 0, 1, 1)
rect.size = self.rect.size
rect.topleft = (p.character.get_x(self), p.character.get_y(self))
if screen.colliderect(rect):
p.to_send.append({'action':'sound','sound':'bump'})
if msg == '<Victim> got rolled over.':
x, y = t.getDir(angle, knockback)
self.move_x(x)
self.move_y(y)
return 'repelled'
final_damage = (damage - self.strength)
if final_damage < 0:
final_damage = 0
self.health -= final_damage
x, y = t.getDir(angle, knockback)
self.move_x(x, 'hurt')
self.move_y(y, 'hurt')
self.hurt_count = 8
if not self.health > 0:
Explosion(self)
for p in self.channel.server.players:
screen = pygame.Rect(0, 0, 1000, 650)
screen.center = p.character.rect.center
if screen.colliderect(self.rect):
p.to_send.append({'action':'sound', 'sound':'die'})
self.channel.text = ''
self.channel.build_to_place = None
self.dead = True
self.deaths += 1
self.barrel_health = 0
self.crates = 0
self.spiky_bushes = 0
self.meal = False
self.moving = 16
if not isinstance(attacker, str):
attacker.kills += 1
username = attacker.channel.username
else:
username = attacker
msg = msg.replace('<Attacker>', username).replace('<Victim>', self.channel.username)
for channel in self.channel.server.players:
channel.message = msg
channel.message_count = 150
channel.message_color = (255,205,0)
if channel == self.channel:
channel.message_color = (255,0,0)
if len(self.channel.get_buildings()) != 0:
self.respawn_count = 200
else:
if not isinstance(attacker, str):
attacker.eliminations += 1
guys = []
for channel in self.channel.server.players:
channel.message = username + ' has eliminated ' + self.channel.username + ' from the game.'
channel.message_count = 150
channel.message_color = (255,205,0)
if channel == self.channel:
channel.message = username + ' has eliminated you from the game!'
channel.message_color = (255,0,0)
if channel.character.dead == False:
guys.append(channel)
elif channel.character.respawn_count > 0:
guys.append(channel)
if len(guys) == 1:
self.channel.server.terminate(guys[0])
self.channel.in_window = False
self.channel.window = None
def suffocate(self):
Explosion(self)
for p in self.channel.server.players:
screen = pygame.Rect(0, 0, 1000, 650)
screen.center = p.character.rect.center
if screen.colliderect(self.rect):
p.to_send.append({'action':'sound', 'sound':'die'})
self.channel.text = ''
self.channel.build_to_place = None
self.dead = True
self.deaths += 1
self.crates = 0
self.meal = False
self.moving = 16
for channel in self.channel.server.players:
channel.message = self.channel.username + ' suffocated.'
channel.message_count = 150
channel.message_color = (255,205,0)
if channel == self.channel:
channel.message_color = (255,0,0)
if len(self.channel.get_buildings()) != 0:
self.respawn_count = 200
else:
guys = []
for channel in self.channel.server.players:
channel.message = self.channel.username + ' has been eliminated from the game by suffocation.'
channel.message_count = 150
channel.message_color = (255,205,0)
if channel == self.channel:
channel.message = 'You suffocated and were eliminated from the game!'
channel.message_color = (255,0,0)
if channel.character.dead == False:
guys.append(channel)
elif channel.character.respawn_count > 0:
guys.append(channel)
if len(guys) == 1:
self.channel.server.terminate(guys[0])
def shoot(self):
if self.shoot_cooldown == 0:
Balloon(self.channel.server, self)
self.shoot_cooldown = self.shot_speed
for p in self.channel.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
screen.center = p.character.rect.center
if screen.colliderect(self.rect):
p.to_send.append({'action':'sound', 'sound':'shot'})
def respawn(self):
self.dead = False
self.x, self.y = self.channel.server.ST_COORDS[self.channel.loc_number]
self.x_flip = 500-self.x
self.y_flip = 325-self.y
self.moving = self.speed
self.channel.message = 'You respawned. You respawn as long as you have buildings alive.'
self.channel.message_count = 150
self.channel.message_color = (128,255,5)
self.health = self.max_health
def get_speed(self):
speed = self.moving
speed /= self.channel.fps
speed *= 30
return speed
resources.py
import pygame
import pygame as p
import random as r
class Farm(pygame.sprite.Sprite):
def __init__(self, server, coords):
pygame.sprite.Sprite.__init__(self, self.gp)
self.x = coords[0]
self.y = coords[1]
self.server = server
self.foods = pygame.sprite.Group()
server.building_blocks.append(pygame.Rect(self.x, self.y, 400, 150))
self.production = 1000
coords = []
while len(list(self.foods)) < 32:
food = Wheat(self, self.foods)
if (food.x, food.y) not in coords:
coords.append((food.x, food.y))
else:
food.kill()
del coords
def update(self):
self.foods.update()
def HandleInput(self, mouse, player):
for food in self.foods:
food.drawrect.x, food.drawrect.y = player.get_x(food), player.get_y(food)
if food.drawrect.collidepoint(mouse[:2]) and bool(mouse[2]) and (food.image == 'good' or food.image == 'mine'):
if not player.dead:
food.mine(player)
return True
return False
class Wheat(pygame.sprite.Sprite):
def __init__(self, farm, gp):
pygame.sprite.Sprite.__init__(self, gp)
self.farm = farm
self.x = r.randint(farm.x, farm.x + 375)
self.y = r.randint(farm.y, farm.y + 40)
self.image = 'good'
self.count = 0
self.mining = 15
self.drawrect = p.Rect(0,0,45,45)
def pick(self, player):
self.image = 'used'
self.count = self.farm.production
player.food += r.randint(1,4)
def mine(self, player):
if self.image == 'good' or self.image == 'mine':
self.image = 'mine'
self.mining -= 1
if self.mining == 0:
self.pick(player)
def update(self):
if self.count > 0:
self.count -= 1
if self.count == 0:
self.image = 'good'
self.mining = 15
for p in self.farm.server.players:
if not p.pending:
self.drawrect.x, self.drawrect.y = p.character.get_x(self), p.character.get_y(self)
screen = pygame.Rect(0, 0, 1000, 650)
if screen.colliderect(self.drawrect):
p.to_send.append({'action':'draw_farm',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'state':self.image})
class Mine(pygame.sprite.Sprite):
def __init__(self, server, coords):
pygame.sprite.Sprite.__init__(self, self.gp)
self.x = coords[0]
self.y = coords[1]
self.server = server
self.golds = pygame.sprite.Group()
server.building_blocks.append(pygame.Rect(self.x, self.y, 200, 600))
self.production = 1000
self.right = self.x > 3000
wall = MineWalls(coords, (200, 18))
server.obs.append(wall)
wall = MineWalls((self.x, self.y + 570), (200, 30))
server.obs.append(wall)
if not self.right:
wall = MineWalls(coords, (30, 600))
server.obs.append(wall)
else:
wall = MineWalls((self.x + 170, self.y), (30, 600))
server.obs.append(wall)
coords = []
while len(list(self.golds)) < 32:
gold = Gold(self, self.golds)
if (gold.x, gold.y) not in coords:
coords.append((gold.x, gold.y))
else:
gold.kill()
del coords
def update(self):
for p in self.server.players:
if not p.pending:
p.to_send.append({'action':'draw_mine',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'right':self.right})
self.golds.update()
def HandleInput(self, mouse, player):
for gold in self.golds:
gold.drawrect.x, gold.drawrect.y = player.get_x(gold), player.get_y(gold)
if gold.drawrect.collidepoint(mouse[:2]) and bool(mouse[2]) and (gold.image == 'good' or gold.image == 'mine'):
if not player.dead:
gold.collect(player)
return True
return False
class Gold(pygame.sprite.Sprite):
def __init__(self, mine, gp):
pygame.sprite.Sprite.__init__(self, gp)
self.mine = mine
self.x = r.randint(mine.x + 30, mine.x + 140)
self.y = r.randint(mine.y + 15, mine.y + 540)
self.image = 'good'
self.count = 0
self.mining = 30
self.drawrect = p.Rect(0,0,45,30)
def pick(self, player):
self.image = 'used'
self.count = self.mine.production
player.gold += r.randint(1,3)
def collect(self, player):
if self.image == 'good' or self.image == 'mine':
self.image = 'mine'
self.mining -= 1
if self.mining == 0:
self.pick(player)
def update(self):
if self.count > 0:
self.count -= 1
if self.count == 0:
self.image = 'good'
self.mining = 30
for p in self.mine.server.players:
if not p.pending:
screen = pygame.Rect(0, 0, 1000, 650)
self.drawrect.x, self.drawrect.y = p.character.get_x(self), p.character.get_y(self)
if screen.colliderect(self.drawrect):
p.to_send.append({'action':'draw_gold',
'coords':(p.character.get_x(self), p.character.get_y(self)),
'state':self.image})
class MineWalls():
def __init__(self, topleft, size):
self.innerrect = pygame.Rect(topleft[0], topleft[1], size[0], size[1])
self.owner = None
def isBuilding(self):
return False
def getHurt(self, damage, attacker):
pass
setup.py
import os
import sys
import json
try:
import text_decoration
except ImportError: # Doesn't matter
class text_decoration:
def rgb(*args): return args[0]
def holiday(): return ''
with open('../preferences.json', 'r') as fo:
preferences = json.loads(fo.read())
py = preferences.get('py', 'python')
newpath = preferences.get('path', [])
sys.path.extend(newpath)
version = f'{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}'
print('Running python version', version)
print()
print()
print('Welcome to VillageWars!')
print(text_decoration.holiday())
print()
print('I hope you enjoy playing it!')
print()
print()
print('Would you like to set preferences? (y/n)')
answer = input('> ').strip()[0].lower()
print()
assert answer in ('y', 'n')
if answer == 'y':
print('What would you like your map\'s theme to be? (please enter one of "' + text_decoration.rgb('grass', (0,200,0)) + '" (default), "' + text_decoration.rgb('pink', (255,200,200)) + '", or "' + text_decoration.rgb('snow', (255,255,255)) + '")')
map = input('> ').lower()
while map not in ['grass', 'pink', 'snow']:
print('That is invalid. Please enter one of "' + text_decoration.rgb('grass', (0,200,0)) + '" (default), "' + text_decoration.rgb('pink', (255,200,200)) + '", or "' + text_decoration.rgb('snow', (255,255,255)) + '".')
map = input('> ').lower()
print()
print('Map set to "' + map + '"')
print()
print('Do you have a prefered python interpreter? (default is "python", but may vary)')
interp = input('> ').lower()
if interp not in ['python', 'py', 'python3', '', 'python.exe', 'py.exe']:
print('That is an unusual interpreter. Please type it again to confirm.')
interp = input('> ').lower()
if interp == '':
interp = 'python'
py = interp
print()
print('Interpreter set to "' + interp + '"')
print()
print('Would you like to specify a missing system path? (type y for yes, n for no, and s to see what is already on the system path)')
answer = 's'
while answer == 's':
answer = input('> ')[0].lower()
print()
if answer == 'n': print('Ok, on to the next step.\n')
elif answer == 's':
print('This is your system path so far:')
print(sys.path)
print()
elif answer == 'y':
print(r'Please enter a directory: (ex: C:\Users\myusername\Appdata\Python3\site-packages)')
path = input('> ')
newpath.append(path)
print()
print('Thank you! Successfully added that to the system path.')
else:
print('Please enter one of "y", "n", or "s".')
preferences = {'map':map, 'py':interp, 'path':newpath}
with open('../preferences.json', 'w') as fo:
fo.write(json.dumps(preferences))
else:
print('Ok, see https://villagewars.fandom.com/wiki/Setting_Preferences to learn how to set them later.')
version_info = False
if len(sys.argv) > 1:
missing_modules = sys.argv[1].split('*')
if 'version_info.json' in missing_modules:
missing_modules.remove('version_info.json')
version_info = True
else:
missing_modules = []
print('You are missing a few elements necessary to start VillageWars.')
print('Would you like these elements to be installed? (y/n)')
answer = input('> ').strip()[0].lower()
if answer == 'n':
print('Ok, well, see you later then!')
print()
input('Press enter to exit')
sys.exit()
assert answer == 'y'
print()
print('You are missing the following third-party modules from VillageWars:')
print()
for module in missing_modules:
print(module)
print()
for module in missing_modules:
input('Press enter to install %s' % module)
exit_code = os.system('{} -m pip install {}'.format(py, module))
if exit_code == 1: # maybe `py` doesn't work.
exit_code = os.system('{} -m pip install {}'.format(py, module))
if exit_code == 1:
print('Hmmm. Is seems like there was an error. Check your internet connection, then try again. If the problem persists, call Aaron.')
print()
input('Press enter to exit.')
sys.exit()
print()
from progress_bar import InitBar as Bar
import send2trash
import requests
print()
input('Press enter to continue')
print()
if version_info:
print('You\'re missing the version information documents that let you update VillageWars. Hold on while those documents are fetched.')
print()
input('Press enter to continue')
print()
print('Collecting version_info.json')
print()
bar = Bar('Downloading:')
bar(0)
res = requests.get('http://villagewars.pythonanywhere.com/download_version_info', stream=True)
res.raise_for_status()
bar(10)
try:
download_size = int(res.headers['Content-length'])
except KeyError:
download_size = 2048
downloaded_bytes = 0
os.makedirs('../../version screenshots', exist_ok=True)
fo = open('../../version screenshots/version_info.json', 'wb')
for chunk in res.iter_content(chunk_size=32):
if chunk: # filter out keep-alive new chunks
len_chunk = len(chunk)
fo.write(chunk)
downloaded_bytes += len_chunk
bar(10 + downloaded_bytes/download_size*90)
bar(100)
del bar
print('Successfully downloaded version information')
fo.close()
print()
print('Successfully installed all necessary elements')
print()
#print('By the way, we are looking for French translators to help me translate the game and the wiki into French. To help me with the wiki, head to villagewars.fandom.com to familiarize yourself with the English wiki and prepare yourself for translating. Don\'t worry, I\'ll help too.')
print('Would you like your files to be refreshed? (Replace out-of-date files) (y/n)')
answer = input('> ').strip()[0].lower()
print()
assert answer in ('y', 'n')
if answer == 'n':
print('Ok, you\'re ready to play VillageWars!')
if answer == 'y':
files = [os.path.abspath('../run/screenshots/' + file) for file in os.listdir('../run/screenshots')]
files.extend([os.path.abspath('../run/compressed/' + file) for file in os.listdir('../run/compressed')])
files.extend([os.path.abspath('../run/downloads/' + file) for file in os.listdir('../run/downloads')])
if len(files):
print('You have %s files to unlink' % len(files))
print()
os.chdir('../')
for file in files:
print(os.path.relpath(file).replace('\\', '/'))
os.chdir('src')
print()
input('Press enter to continue')
print()
#print('Unlinking %s files:' % len(files), end=' ')
bar = Bar('Unlinking %s files' % len(files))
bar(0)
for i, file in enumerate(files):
send2trash.send2trash(file)
bar(((i+1)/len(files)*100))
del bar
print()
print('Sucessfully refreshed your files')
else:
print('Nevermind, you don\'t have any files to refresh.')
print()
print('You\'re ready to play VillageWars!')
print()
input('Press enter to continue to VillageWars')
os.chdir('../')
os.system(py + ' -m main')
toolbox.py
import pygame
from pygame.locals import *
import math
import socket, subprocess
def black_and_white(surface, change=0):
width = surface.get_width()
height = surface.get_height()
surf = surface.__copy__()
for x in range(width):
for y in range(height):
color = list(surface.get_at((x, y)))
alpha = color.pop()
color = [max(0, min(255, (sum(color)/3)+change)) for i in range(3)]
color.append(alpha)
#if alpha > 200:
surf.set_at((x, y), tuple(color))
return surf
width = surface.get_width()
height = surface.get_height()
surf = pygame.Surface((width, height))
surf.fill((100,100,100))
for x in range(width):
for y in range(height):
color = list(surface.get_at((x, y)))
alpha = color.pop()
color = [sum(color)/3 for i in range(3)]
color.append(alpha)
#if alpha > 200:
surf.set_at((x, y), tuple(color))
return surf
class Button:
def __init__(self, screen, image='', image_hover='', image_down='', image_off='', off=False, assets='../assets/', accepts=None, **kwargs): # give pygame.Rect kwargs
if accepts is None:
self.accepts = [1] # Left Click only
else:
self.accepts = accepts
assert type(assets) == str
self.screen = screen
try:
self.image = pygame.image.load(assets + image)
except FileNotFoundError:
self.image = pygame.Surface((0,0))
try:
self.image_hov = pygame.image.load(assets + image_hover)
except FileNotFoundError:
pass
try:
self.image_down = pygame.image.load(assets + image_down)
except FileNotFoundError:
pass
try:
self.image_no = pygame.image.load(assets + image_off)
except FileNotFoundError:
pass
self.on = not off
try:
self.rect = self.image.get_rect(**kwargs)
except Exception as exc:
self.rect = self.image_off.get_rect(**kwargs)
self.state = ('idle' if self.on else 'off')
@property
def x(self):
return self.rect.x
@x.setter
def x(self, value):
self.rect.x = value
@property
def y(self):
return self.rect.y
@y.setter
def y(self, value):
self.rect.y = value
@classmethod
def from_surf(cls, screen, image=None, image_hover=None, image_down=None, image_off=None, off=False, **kwargs):
button = Button(screen, assets='filenotfounderror.png', off=off)
if image:
button.image = image
if image_hover:
button.image_hov = image_hover
if image_down:
button.image_down = image_down
if image_off:
button.image_no = image_off
button.rect = button.image.get_rect(**kwargs)
return button
def handle_event(self, event):
in_coords = self.rect.collidepoint(pygame.mouse.get_pos()[:2])
if event.type not in (MOUSEBUTTONDOWN, MOUSEBUTTONUP, MOUSEMOTION):
return
if self.state == 'idle':
if event.type == pygame.MOUSEBUTTONDOWN and in_coords and event.button in self.accepts:
self.state = 'armed'
elif self.state == 'armed':
if event.type == MOUSEBUTTONUP and in_coords and event.button in self.accepts:
self.state = 'idle'
self.draw()
return event.button
if event.type == MOUSEMOTION and not in_coords:
self.state = 'disarmed'
elif self.state == 'disarmed':
if event.type == MOUSEMOTION and in_coords:
self.state = 'armed'
elif event.type == MOUSEBUTTONUP and event.button in self.accepts:
self.state = 'idle'
return False
def draw(self):
in_coords = self.rect.collidepoint(pygame.mouse.get_pos()[:2])
self.down = pygame.mouse.get_pressed()[0]
if self.state == 'armed':
self.screen.blit(self.image_down, self.rect)
elif self.state == 'idle' or self.state == 'disarmed':
if in_coords and (not self.down):
self.screen.blit(self.image_hov, self.rect)
else:
self.screen.blit(self.image, self.rect)
elif self.state == 'off':
self.screen.blit(self.image_no, self.rect)
def rotate(image, rect, angle):
"""
rotate returns the rotated version of image and the rotated image's rectangle.
"""
# Get a new image that is the original image but rotated
new_image = pygame.transform.rotate(image, angle)
# Get a new rect with the center of the old rect
new_rect = new_image.get_rect(center=rect.center)
return new_image, new_rect
def getDist(x1, y1, x2, y2):
"""
getDist returns the distance between (x1, y1) and (x2, y2).
"""
x = abs(x1-x2)
y = abs(y1-y2)
return math.sqrt(x*x+y*y)
def getAngle(x1, y1, x2, y2):
"""
getAnlge returns the angle (x1, y1) should be at if it is facing (x2, y2).
"""
x_difference = x2-x1
y_differnece = y2-y1
return math.degrees(math.atan2(-y_differnece, x_difference))
def getDir(angle, total=1):
"""
returns (x, y) where x and y are the distance moved if the unit is moving at the angle.
"""
angle_rads = math.radians(angle)
x_move = math.cos(angle_rads) * total
y_move = -(math.sin(angle_rads) * total)
return x_move, y_move
def centerXY(thing, screen):
"""
centeringCoords returns the coords that will put thing in the center of the screen.
"""
new_x = screen.get_width()/2 - thing.get_width()/2
new_y = screen.get_height()/2 - thing.get_height()/2
return new_x, new_y
class keyDownListener():
"""
keyDownListener keeps track of one key and says when it gets pressed down.
self.down will be True once every time the key is pressed and False otherwise.
"""
def __init__(self):
self.down = False
self.is_up = False
def update(self, key_pressed):
if not key_pressed:
self.is_up = True
self.down = False
else:
if self.is_up:
self.down = True
else:
self.down = False
self.is_up = False
def getMyIP():
"""
getMyIP returns the IP address on the computer you run it on.
This may not work properly if you're not connected to the internet.
(If this code seems super complicated, don't worry.. I don't understand it either -Andy)
"""
return str((([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")]
or [[(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]])
+ ["no IP found"])[0])
def network():
raw_wifi = subprocess.check_output(['netsh', 'WLAN', 'show', 'interfaces'])
data_strings = raw_wifi.decode('utf-8').split()
try:
index = data_strings.index('Profile')
except:
return None
return data_strings[index + 2]
def copy(theList):
return theList[:]
def getVersionInt(version_str):
parts = version_str.split('.')
return int(parts[0]) * 10000 + int(parts[1]) * 100 + int(parts[2])
typer.py
import pyperclip
import pygame as p
from pygame.locals import *
from time import monotonic
class Typing:
def __init__(self, character='|', block=['@', '/', '.', ' ']):
self.typing = character
self.character = character
self.shifting = False
self.ctrling = False
self.block = block
@property
def result(self):
return self.typing[:self.typing.find(self.character)] + self.typing[self.typing.find(self.character) + 1:]
def shift(self):
self.shifting = not self.shifting
def ctrl(self):
self.ctrling = not self.ctrling
def type(self, event):
if event.key == K_a:
self.add('a')
if event.key == K_b:
self.add('b')
if event.key == K_c:
self.add('c')
if event.key == K_d:
self.add('d')
if event.key == K_e:
self.add('e')
if event.key == K_f:
self.add('f')
if event.key == K_g:
self.add('g')
if event.key == K_h:
self.add('h')
if event.key == K_i:
self.add('i')
if event.key == K_j:
self.add('j')
if event.key == K_k:
self.add('k')
if event.key == K_l:
self.add('l')
if event.key == K_m:
self.add('m')
if event.key == K_n:
self.add('n')
if event.key == K_o:
self.add('o')
if event.key == K_p:
self.add('p')
if event.key == K_q:
self.add('q')
if event.key == K_r:
self.add('r')
if event.key == K_s:
self.add('s')
if event.key == K_t:
self.add('t')
if event.key == K_u:
self.add('u')
if event.key == K_v and not self.ctrling:
self.add('v')
if event.key == K_w:
self.add('w')
if event.key == K_x:
self.add('x')
if event.key == K_y:
self.add('y')
if event.key == K_z:
self.add('z')
if event.key == K_1:
self.add('1')
if event.key == K_2:
self.add('2')
if event.key == K_3:
self.add('3')
if event.key == K_4:
self.add('4')
if event.key == K_5:
self.add('5')
if event.key == K_6:
self.add('6')
if event.key == K_7:
self.add('7')
if event.key == K_8:
self.add('8')
if event.key == K_9:
self.add('9')
if event.key == K_0:
self.add('0')
if event.key == K_PERIOD:
self.add('.')
if event.key == K_SLASH:
self.add('/')
if event.key == K_SPACE:
self.add(' ')
if event.key == K_BACKSPACE:
self.typing = self.typing[:-2] + self.character
if event.key == K_v and self.ctrling:
self.typing = self.typing[:self.typing.find(self.character)] + pyperclip.paste() + self.typing[self.typing.find(self.character):]
def add(self, letter):
if self.shifting:
letter = letter.upper()
if letter == '2':
letter = '@'
if letter not in self.block:
self.typing = self.typing[:self.typing.find(self.character)] + letter + self.typing[self.typing.find(self.character):]
def text(self):
if monotonic() % 1.2 > 0.6:
return self.typing[:-1]
return self.typing
VillageWarsClient.py
import shelve
import os
import sys
import json
with open('../preferences.json', 'r') as fo:
preferences = json.loads(fo.read())
py = preferences.get('py', 'python')
path = preferences.get('path', [])
sys.path.extend(path)
import requests
import json
import math as m
from time import monotonic, sleep
import random as ran
from progress_bar import InitBar as Bar
import pygame
import threading
import os
import re
import menu
import threading
from net2web import Client as ParentClient, getmyip
import pygame as p
from pygame.locals import *
from pymsgbox import *
import GameClient
import toolbox
import toolbox as t
import typer
import pyperclip
import logging as log
log.basicConfig(level=log.INFO, format='%(levelname)s - %(message)s')
path = os.path.abspath('.')
if not path.endswith('src'):
os.chdir('src/')
regex = re.compile(r'(\d)+\.(\d)+\.(\d)+')
__version__ = regex.search(path).group()
print('Running VillageWars version', __version__)
music_playing = True
p.mixer.pre_init(buffer=5)
p.mixer.init()
DOWNLOAD = False
p.font.init()
icon = p.image.load('../assets/Skins/0.png')
skins = [p.transform.scale(p.image.load('../assets/Skins/%s.png' % (i)), (280, 280)) for i in range(len(os.listdir('../assets/Skins')) // 2)]
click_sound = p.mixer.Sound('../assets/sfx/click.wav')
title = p.transform.scale(p.image.load('../assets/title page/attempt 1.png'), (500, 100))
title_rect = title.get_rect(midtop=(500, 30))
SigningIn = p.image.load('../assets/SigningIn.png')
CreatingAcount = p.image.load('../assets/CreatingAcount.png')
Connecting = SigningIn
cursor = p.cursors.Cursor(p.SYSTEM_CURSOR_ARROW)
def get_uns(username):
font = p.font.SysFont('default', 90)
return font.render(username, True, (255, 0, 0)), font.render(username, True, (0, 0, 255)), font.render(username, True, (255, 255, 0)), font.render(username, True, (0, 255, 0))
def getScreen(resizable=False):
p.init()
if resizable:
screen = p.display.set_mode((1000, 650), p.RESIZABLE)
else:
screen = p.display.set_mode((1000, 650))
p.display.set_icon(icon)
clock = p.time.Clock()
return screen, clock
def loading_circle(screen, clock):
base_screen = screen.__copy__()
dark = p.Surface((1000,650))
dark.set_alpha(50)
base_screen.blit(dark, (0,0))
global stop_loading_circle
stop_loading_circle = False
circle = p.image.load('../assets/title page/loading.png')
circle_angle = 0
circle_speed = 5
circle_rect = circle.get_rect(center=(500, 325))
while not stop_loading_circle:
for ev in pygame.event.get():
if ev.type == QUIT:
p.quit()
sys.exit()
screen.blit(base_screen, (0,0))
circle_angle += circle_speed
circled = p.transform.rotate(circle, circle_angle)
circle_rect = circled.get_rect(center=circle_rect.center)
screen.blit(circled, circle_rect)
p.display.update()
clock.tick(60)
def logIn(screen, clock, logInType, username, password, name='', email='None'):
base_screen = screen.__copy__()
global response_data
def CheckValidUser(username, password):
global response_data
res = requests.get(flask_application + 'get_user/%s/%s' % (username, password))
res.raise_for_status()
response_data = res.json()
def CreateAccount(username, password, name, email):
global response_data
res = requests.post(flask_application + 'create', data={'username':username, 'password':password, 'name':name, 'email':str(email)})
res.raise_for_status()
response_data = res.json()
if logInType == 'sign in':
CheckValidUser(username, password)
elif logInType == 'sign up':
CreateAccount(username, password, name, email)
return response_data
def rand_rgb(r,g,b,rd,gd,bd):
rd += ran.randint(-16,16)/1000
gd += ran.randint(-16,16)/1000
bd += ran.randint(-16,16)/1000
if abs(rd) > 20:
rd = 0
if abs(gd) > 20:
gd = 0
if abs(bd) > 20:
bd = 0
r += rd
g += gd
b += bd
if r > 255 or r < 0:
rd = -rd
r += rd * 2
if g > 255 or g < 0:
gd = -gd
g += gd * 2
if b > 255 or b < 0:
bd = -bd
b += bd * 2
return r, g, b, rd, gd, bd
def get_nametag_color(color, username):
font40 = p.font.SysFont('default', 40)
font120 = p.font.SysFont('default', 120)
small = font40.render(username, True, color)
big = font120.render(username, True, color)
return small, big
def search_servers(screen, choose):
global INTERNET
if INTERNET:
res = requests.post(flask_application + 'scan_for_servers')
res.raise_for_status()
servers = res.json()['IPs']
global server_buttons
server_buttons = server_surfs(servers, screen, choose)
else:
if check_internet(5):
INTERNET = True
return search_servers(screen, choose)
else:
INTERNET = False
servers = []
server_buttons = server_surfs(servers, screen, choose)
global FOUND_SERVERS
FOUND_SERVERS = True
def server_surfs(IPs, screen, choose_server_rect):
server_buttons = []
gray_rectangle = p.Surface((800, 60))
gray_rectangle.fill((180,180,180))
gray_rectangle2 = p.Surface((800, 60))
gray_rectangle2.fill((180,180,240))
gray_rectangle3 = p.Surface((800, 60))
gray_rectangle3.fill((175,160,175))
font_server = p.font.SysFont('default', 50)
smfont = p.font.SysFont('default', 40)
y = choose_server_rect.bottom + 50
for server in IPs:
name = server['name']
ip = server['ip']
if ip.upper() == ip.lower():
ip_surf = font_server.render(ip, True, (0,0,90))
ip_surf2 = font_server.render(ip, True, (50,50,50))
ip_surf3 = font_server.render(ip, True, (0,0,0))
else:
ip_surf = font_server.render('1.7.1 Online', True, (0,0,90))
ip_surf2 = font_server.render('1.7.1 Online', True, (50,50,50))
ip_surf3 = font_server.render('1.7.1 Online', True, (0,0,0))
ip_rect = ip_surf.get_rect(midright=(gray_rectangle.get_width() - 20, gray_rectangle.get_height() // 2))
name_surf = font_server.render(name, True, (0,0,0))
name_surf2 = font_server.render(name, True, (30,30,40))
name_rect = name_surf.get_rect(midleft=(20, gray_rectangle.get_height() // 2))
if server['started']:
displayed = 'Game has started'
gray_rectangle.fill((100,100,100))
gray_rectangle2.fill((100,100,140))
gray_rectangle3.fill((85,75,85))
else:
displayed = server['gamemode']
gray_rectangle.fill((180,180,180))
gray_rectangle2.fill((180,180,240))
gray_rectangle3.fill((175,160,175))
r = gray_rectangle.__copy__()
r2 = gray_rectangle2.__copy__()
r3 = gray_rectangle3.__copy__()
gamemode_surf = smfont.render(displayed, True, (50,50,199))
gamemode_rect = gamemode_surf.get_rect(midleft=(name_rect.right + 20, gray_rectangle.get_height() // 2))
r.blit(ip_surf, ip_rect)
r2.blit(ip_surf2, ip_rect)
r3.blit(ip_surf3, ip_rect)
r.blit(name_surf, name_rect)
r2.blit(name_surf2, name_rect)
r3.blit(name_surf, name_rect)
r.blit(gamemode_surf, gamemode_rect)
r2.blit(gamemode_surf, gamemode_rect)
r3.blit(gamemode_surf, gamemode_rect)
button = {
'button':t.Button.from_surf(screen, r, r2, r3, midtop=(500, y)),
'ip':ip
}
server_buttons.append(button)
y += 60
return server_buttons
def loggedIn(screen, clock, port, username, userInfo):
global FOUND_SERVERS, server_buttons
color = userInfo['color']
username_surf_small, username_surf_big = get_nametag_color(color, username)
skin_num = userInfo['skin']
skin_original_size = skins[skin_num]
skins_not = [t.black_and_white(p.transform.scale(skin, (200,200)), change=30) for skin in skins]
skins_not_not = [t.black_and_white(p.transform.scale(skin, (120,120)), change=20) for skin in skins]
coins = userInfo['coins']
# State Constants (Local to avoid confusion)
SPLASH = 'splash'
PROFILE = 'profile'
SINGLEPLAYER = 'singleplayer'
MULTIPLAYER = 'multiplayer'
CHANGE_COLOR = 'change_color'
CHANGE_SKIN = 'change_skin'
CHOOSE_SERVER = 'choose_server'
state = SPLASH
multiplayer_button = t.Button(screen, 'multiplayer.png', 'multiplayer_hov.png', 'multiplayer_down.png', 'multiplayer_no.png', midtop=(500, 300))
singleplayer_button = t.Button(screen, 'singleplayer.png', 'singleplayer_hov.png', 'singleplayer_down.png', 'singleplayer_no.png', off=True, midtop=(500, 200))
profile_button = t.Button(screen, 'profile.png', 'profile_hov.png', 'profile_down.png', 'profile_no.png', midtop=(500, 400))
profile_back_button = t.Button(screen, 'back.png', 'back_hov.png', 'back_down.png', midtop=(500, 500))
change_skin_button = t.Button(screen, 'change skin.png', 'change skin_hov.png', 'change skin_down.png', midtop=(500, 300))
change_color_button = t.Button(screen, 'change color.png', 'change color_hov.png', 'change color_down.png', midtop=(500, 200))
skin_back_button = t.Button(screen, 'back.png', 'back_hov.png', 'back_down.png', midbottom=(500, 610))
color_back_button = t.Button(screen, 'back.png', 'back_hov.png', 'back_down.png', midbottom=(500, 610))
server_back_button = t.Button(screen, 'back.png', 'back_hov.png', 'back_down.png', midbottom=(500, 620))
server_refresh_button = t.Button(screen, 'refresh.png', 'refresh_hov.png', 'refresh_down.png', midbottom=(500, 480))
server_direct_button = t.Button(screen, 'direct.png', 'direct_hov.png', 'direct_down.png', midbottom=(500, 550))
red = p.Surface((60, 60))
red.fill((255,0,0)) # Red
red2 = red.__copy__()
red2.fill((255,50,50))
red3 = red.__copy__()
red3.fill((200,10,10))
blue = p.Surface((60, 60))
blue.fill((0,0,255)) # Blue
blue2 = blue.__copy__()
blue2.fill((50,50,255))
blue3 = blue.__copy__()
blue3.fill((10,10,200))
yellow = p.Surface((60, 60))
yellow.fill((255,255,0)) # Yellow
yellow2 = yellow.__copy__()
yellow2.fill((255,255,100))
yellow3 = yellow.__copy__()
yellow3.fill((227,227,20))
green = p.Surface((60, 60))
green.fill((0,255,0)) # Green
green2 = green.__copy__()
green2.fill((100,255,100))
green3 = green.__copy__()
green3.fill((10,200,10))
red_button = t.Button.from_surf(screen, red, red2, red3, midtop=(700, 250))
blue_button = t.Button.from_surf(screen, blue, blue2, blue3, midtop=(760, 250))
yellow_button = t.Button.from_surf(screen, yellow, yellow2, yellow3, midtop=(820, 250))
green_button = t.Button.from_surf(screen, green, green2, green3, midtop=(880, 250))
font100 = p.font.SysFont('default', 100)
font40 = p.font.SysFont('default', 40)
title = font100.render('VillageWars', True, (128,0,128))
fo = open('tips.json', 'r')
tips = json.loads(fo.read())
fo.close()
tip = ran.choice(tips['rare_tips'])
tip = font40.render(tip, True, (255,205,0))
tip_rect = tip.get_rect(midbottom=(500, 620))
choose_server_surf = font100.render('Servers', True, (20,20,20))
choose_server_rect = choose_server_surf.get_rect(midtop=(500, 50))
scanning_surf = font40.render('Scanning for servers...', True, (20,20,20))
scanning_rect = scanning_surf.get_rect(midtop=(500, choose_server_rect.bottom + 50))
r = 10
g = 10
b = 20
rd, gd, bd = 0.3, 0.1, 1
global stop_loading_circle
stop_loading_circle = True
while True:
width, height = screen.get_size()
title_rect = title.get_rect(midtop=(width//2, (10 * (m.sin(monotonic() * 2))) + 30)) # Update title location
mouse = p.mouse.get_pos()
click = p.mouse.get_pressed()
for event in pygame.event.get():
if event.type == QUIT:
p.quit()
sys.exit()
if state == SPLASH:
if multiplayer_button.handle_event(event):
state = CHOOSE_SERVER
rd, gd, bd = 0.3, 0.1, 0.5
FOUND_SERVERS = False
thread = threading.Thread(target=search_servers, args=[screen, choose_server_rect])
thread.start()
if singleplayer_button.handle_event(event):
pass # Doesn't do anything (for now)
if profile_button.handle_event(event):
state = PROFILE
rd, gd, bd = 0.3, 0.1, 0.5
if state == PROFILE:
if profile_back_button.handle_event(event):
state = SPLASH
rd, gd, bd = 0, 0, 0
if change_skin_button.handle_event(event):
state = CHANGE_SKIN
rd, gd, bd = 0.3, 0.1, 0.5
if change_color_button.handle_event(event):
state = CHANGE_COLOR
rd, gd, bd = 0.3, 0.1, 0.5
if state == CHANGE_SKIN:
if skin_back_button.handle_event(event):
state = PROFILE
rd, gd, bd = 0.3, 0.1, 0.5
if event.type == KEYUP and event.key == K_LEFT:
skin_num -= 1
if skin_num == -1:
skin_num = len(skins) - 1
skin_original_size = skins[skin_num]
if event.type == KEYUP and event.key == K_RIGHT:
skin_num += 1
if skin_num == len(skins):
skin_num = 0
skin_original_size = skins[skin_num]
if state == CHANGE_COLOR:
if color_back_button.handle_event(event):
state = PROFILE
rd, gd, bd = 0.3, 0.1, 0.5
if red_button.handle_event(event):
color = (255,0,0)
username_surf_small, username_surf_big = get_nametag_color(color, username)
if blue_button.handle_event(event):
color = (0,0,255)
username_surf_small, username_surf_big = get_nametag_color(color, username)
if yellow_button.handle_event(event):
color = (255,255,0)
username_surf_small, username_surf_big = get_nametag_color(color, username)
if green_button.handle_event(event):
color = (0,255,0)
username_surf_small, username_surf_big = get_nametag_color(color, username)
if state == CHOOSE_SERVER:
if server_back_button.handle_event(event):
state = SPLASH
rd, gd, bd = 0.3, 0.1, 0.5
if FOUND_SERVERS:
for button in server_buttons:
if button['button'].handle_event(event):
thread = threading.Thread(target=loading_circle, args=(screen, clock))
thread.start()
return {'color':color,
'skin':skin_num,
'coins':coins,
'xp':userInfo['xp'],
'ip':button['ip']}
if server_refresh_button.handle_event(event):
FOUND_SERVERS = False
thread = threading.Thread(target=search_servers, args=[screen, choose_server_rect])
thread.start()
if server_direct_button.handle_event(event):
ip = prompt('Enter the server\'s IP address:', title='VillageWars')
if ip and ip != 'Cancel':
thread = threading.Thread(target=loading_circle, args=(screen, clock))
thread.start()
return {'color':color,
'skin':skin_num,
'coins':coins,
'xp':userInfo['xp'],
'ip':ip}
if state == SPLASH:
r, g, b, rd, gd, bd = rand_rgb(r,g,b,rd,gd,bd)
screen.fill((50,160,50))
multiplayer_button.draw()
singleplayer_button.draw()
profile_button.draw()
screen.blit(tip, tip_rect)
# Skin Displayer
skin = p.transform.scale(skin_original_size, (100, 100))
skin_rect = skin.get_rect(center=(140, 325))
angle = t.getAngle(140, 325, *(p.mouse.get_pos()[:2]))
skin, skin_rect = t.rotate(skin, skin_rect, angle)
screen.blit(skin, skin_rect)
screen.blit(title, title_rect)
username_rect = username_surf_small.get_rect(midbottom=skin_rect.midtop)
screen.blit(username_surf_small, username_rect)
if state == CHOOSE_SERVER:
r, g, b, rd, gd, bd = rand_rgb(r,g,b,rd,gd,bd)
screen.fill((90,100,255))
server_back_button.draw()
server_refresh_button.draw()
server_direct_button.draw()
if FOUND_SERVERS:
for button in server_buttons:
button['button'].draw()
else:
screen.blit(scanning_surf, scanning_rect)
screen.blit(choose_server_surf, choose_server_rect)
if state == PROFILE:
r, g, b, rd, gd, bd = rand_rgb(r,g,b,rd,gd,bd)
screen.fill((r,g,b))
profile_back_button.draw()
change_skin_button.draw()
change_color_button.draw()
# Skin Displayer
skin = p.transform.scale(skin_original_size, (100, 100))
skin_rect = skin.get_rect(center=(140, 325))
angle = t.getAngle(140, 325, *(p.mouse.get_pos()[:2]))
skin, skin_rect = t.rotate(skin, skin_rect, angle)
screen.blit(skin, skin_rect)
username_rect = username_surf_small.get_rect(midbottom=skin_rect.midtop)
screen.blit(username_surf_small, username_rect)
if state == CHANGE_COLOR:
r, g, b, rd, gd, bd = rand_rgb(r,g,b,rd,gd,bd)
screen.fill((r,g,b))
color_back_button.draw()
skin = p.transform.scale(skin_original_size, (300, 300))
skin_rect = skin.get_rect(center=(400, 325))
screen.blit(skin, skin_rect)
username_rect = username_surf_big.get_rect(midbottom=skin_rect.midtop)
screen.blit(username_surf_big, username_rect)
red_button.draw()
blue_button.draw()
yellow_button.draw()
green_button.draw()
if state == CHANGE_SKIN:
r, g, b, rd, gd, bd = rand_rgb(r,g,b,rd,gd,bd)
screen.fill((r,g,b))
skin_back_button.draw()
# Skin Displayer
if skin_num == 0:
skin = p.transform.scale(skin_original_size, (300, 300))
rskin_rect = skin.get_rect(center=(500, 325))
screen.blit(skin, rskin_rect)
skin_rect = skins_not_not[3].get_rect(center=(40, 325))
screen.blit(skins_not_not[3], skin_rect)
skin_rect = skins_not[4].get_rect(center=(220, 325))
screen.blit(skins_not[4], skin_rect)
skin_rect = skins_not[1].get_rect(center=(780, 325))
screen.blit(skins_not[1], skin_rect)
skin_rect = skins_not_not[2].get_rect(center=(960, 325))
screen.blit(skins_not_not[2], skin_rect)
if skin_num == 1:
skin = p.transform.scale(skin_original_size, (300, 300))
rskin_rect = skin.get_rect(center=(500, 325))
screen.blit(skin, rskin_rect)
skin_rect = skins_not_not[4].get_rect(center=(40, 325))
screen.blit(skins_not_not[4], skin_rect)
skin_rect = skins_not[0].get_rect(center=(220, 325))
screen.blit(skins_not[0], skin_rect)
skin_rect = skins_not[2].get_rect(center=(780, 325))
screen.blit(skins_not[2], skin_rect)
skin_rect = skins_not_not[3].get_rect(center=(960, 325))
screen.blit(skins_not_not[3], skin_rect)
if skin_num == 2:
skin = p.transform.scale(skin_original_size, (300, 300))
rskin_rect = skin.get_rect(center=(500, 325))
screen.blit(skin, rskin_rect)
skin_rect = skins_not_not[0].get_rect(center=(40, 325))
screen.blit(skins_not_not[0], skin_rect)
skin_rect = skins_not[1].get_rect(center=(220, 325))
screen.blit(skins_not[1], skin_rect)
skin_rect = skins_not[3].get_rect(center=(780, 325))
screen.blit(skins_not[3], skin_rect)
skin_rect = skins_not_not[4].get_rect(center=(960, 325))
screen.blit(skins_not_not[4], skin_rect)
if skin_num == 3:
skin = p.transform.scale(skin_original_size, (300, 300))
rskin_rect = skin.get_rect(center=(500, 325))
screen.blit(skin, rskin_rect)
skin_rect = skins_not_not[1].get_rect(center=(40, 325))
screen.blit(skins_not_not[1], skin_rect)
skin_rect = skins_not[2].get_rect(center=(220, 325))
screen.blit(skins_not[2], skin_rect)
skin_rect = skins_not[4].get_rect(center=(780, 325))
screen.blit(skins_not[4], skin_rect)
skin_rect = skins_not_not[0].get_rect(center=(960, 325))
screen.blit(skins_not_not[0], skin_rect)
if skin_num == 4:
skin = p.transform.scale(skin_original_size, (300, 300))
rskin_rect = skin.get_rect(center=(500, 325))
screen.blit(skin, rskin_rect)
skin_rect = skins_not_not[2].get_rect(center=(40, 325))
screen.blit(skins_not_not[2], skin_rect)
skin_rect = skins_not[3].get_rect(center=(220, 325))
screen.blit(skins_not[3], skin_rect)
skin_rect = skins_not[0].get_rect(center=(780, 325))
screen.blit(skins_not[0], skin_rect)
skin_rect = skins_not_not[1].get_rect(center=(960, 325))
screen.blit(skins_not_not[1], skin_rect)
username_rect = username_surf_big.get_rect(midbottom=rskin_rect.midtop)
screen.blit(username_surf_big, username_rect)
p.display.update()
clock.tick(60)
p.display.set_caption('VillageWars ' + __version__)
return {'color':color,
'xp':userInfo['xp'],
'skin':skin_num,
'coins':userInfo['coins'],
'ip':ip}
def joinGame(screen, clock, ip, port, username, newUserInfo):
global music_playing
music_playing = GameClient.main(screen, clock, username, __version__, newUserInfo, ip, port=port, musicPlaying=music_playing)
if music_playing:
p.mixer.music.load('../assets/sfx/menu.wav')
p.mixer.music.play(-1, 0.0)
def check_internet(timeout=2):
try:
requests.head("http://villagewars.pythonanywhere.com/test_connection", timeout=timeout)
this = True
except:
this = False
try:
with open('../../version screenshots/version_info.json', 'r') as data_file:
version_data = json.loads(data_file.read())
active = version_data['active']
except:
active = '0.0.1'
if this == True:
res = requests.get('http://villagewars.pythonanywhere.com/need_version_info/' + active)
res.raise_for_status()
if res.json()['need']:
bar = Bar('Updating Launcher')
bar(0)
res = requests.get('http://villagewars.pythonanywhere.com/download_version_info', stream=True)
res.raise_for_status()
try:
download_size = int(res.headers['Content-length'])
except KeyError:
download_size = 2048
downloaded_bytes = 0
os.makedirs('../../version screenshots', exist_ok=True)
fo = open('../../version screenshots/version_info.json', 'wb')
for chunk in res.iter_content(chunk_size=32):
if chunk: # filter out keep-alive new chunks
len_chunk = len(chunk)
fo.write(chunk)
downloaded_bytes += len_chunk
bar(downloaded_bytes/download_size*100)
fo.close()
bar(100)
del bar
print('Successfully downloaded version information')
return this
def main():
screen, clock = getScreen(resizable=False)
userInfo = {'valid':False}
while not userInfo['valid']:
result = menu.runMenu(screen, clock)
username, password = result['username'], result['password']
global stop_loading_circle
stop_loading_circle = False
circle = threading.Thread(target=loading_circle, args=[screen, clock])
circle.start()
if not INTERNET:
username = 'Guest' + str(ran.randint(1,999)).rjust(3, '0')
userInfo = {'valid':True,'username':username,'color':(255,0,0),'skin':0,'coins':0,'xp':0}
alert('We were unable to sign you in. Play local!\n Name: ' + username)
elif result['create']:
name, email = result['name'], result['email']
userInfo = logIn(screen, clock, 'sign up', username, password, name, email=email)
else:
userInfo = logIn(screen, clock, 'sign in', username, password)
if not userInfo['valid']:
alert(userInfo['message'], title='VillageWars')
stop_loading_circle = True
newUserInfo = loggedIn(screen, clock, 5555, username, userInfo)
if not username.startswith('Guest'):
res = requests.post(flask_application + 'updateUser', data={'username':username, 'color':json.dumps(newUserInfo['color']), 'skin':str(newUserInfo['skin'])})
res.raise_for_status()
joinGame(screen, clock, newUserInfo['ip'], 5555, username, newUserInfo)
if __name__ == '__main__':
if check_internet(5):
INTERNET = True
else:
INTERNET = False
flask_application = 'http://villagewars.pythonanywhere.com/'
main()
VillageWarsServer.py
from time import sleep, localtime, time
from weakref import WeakKeyDictionary
import socket
import shelve
import pygame
import os
import json
import sys
import toolbox
from lobbyAvatar import LobbyAvatar
import time
from player import Character
from background import Background
import obstacle
from building import *
from balloon import Balloon
from resources import Farm, Mine
from NPC import *
import logging as log
from hacking import *
from animations import *
from events import *
import random
import zipfile2
import threading
import re
import requests
BUILDINGS = CentralBuilding, PortableCentralBuilding, MinersGuild, FarmersGuild, Balloonist, Inn, FitnessCenter, Gym, RunningTrack, HealthCenter, ConstructionSite, RobotFactory, ArcheryTower, BarrelMaker, BotanistsLab, RepairCenter, Ranch, AlchemistsLab, Market, TownHall, AdvancedBalloonistBuilding, Builders, RetiredBarbarianOutpost, AdventuringCenter
from net2web import Channel as ParentChannel, Server as ParentServer, getmyip
with open('../preferences.json', 'r') as fo:
preferences = json.loads(fo.read())
py = preferences.get('py', 'python')
path = preferences.get('path', [])
sys.path.extend(path)
def compress_version(skip=[]):
global log
log.debug('Starting Compression...')
global version
zipFilename = version + '.zip'
log.debug(f'Creating {zipFilename}...')
versionZip = zipfile2.ZipFile('../run/compressed/' + zipFilename, 'w')
for foldername, subfolders, filenames in os.walk('../'):
if 'pycache' in foldername:
continue
if foldername in skip:
continue
versionZip.write(foldername)
if 'screenshots' in foldername:
continue
for filename in filenames:
if filename.endswith('.zip'):
continue
if filename.endswith('serverlog.txt'):
continue
if os.path.basename(filename) in skip:
continue
log.debug(f'Adding {os.path.basename(filename)}...')
versionZip.write(foldername + '/' + filename)
log.debug('Wrapping Up...')
versionZip.close()
log.debug('Finished!')
def getVersionInt(version_str):
parts = version_str.split('.')
return int(parts[0]) * 10000 + int(parts[1]) * 100 + int(parts[2])
class Walls():
def __init__(self, server, direction):
if direction == 'left-right':
self.innerrect = pygame.Rect(0, 1860, 6000, 180)
elif direction == 'up-down':
self.innerrect = pygame.Rect(2965, 0, 80, 3900)
server.building_blocks.append(self.innerrect)
self.dir = direction
self.count = round(30 * 60 * WALLS_TIME)
self.server = server
server.obs.append(self)
self.owner = None
def update(self):
if self.count > 0:
self.count -= 1
if self.count == 0:
if self.dir == 'up-down':
self.server.Fall()
self.server.building_blocks.remove(self.innerrect)
self.server.obs.remove(self)
def getHurt(self, damage, attacker):
pass
def isBuilding(self):
return False
def explode(self):
pass
class ClientChannel(ParentChannel):
"""
This is the server representation of a single connected client.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.pending = True
self.number = 0
self.color = (0,0,0)
self.ishost = False
self.lobby_avatar = None
self.username = 'Anonymous'
self.messages = []
self.buildings = []
self.in_window = False
self.in_innpc_window = False
self.window = None
self.text = ''
self.build_to_place = None
self.fps = 30
self.com = False
self.version = '0.0.0'
self.ver_int = getVersionInt(self.version)
self.to_send = []
@property
def message_color(self):
if len(self.messages):
return self.messages[-1]['color']
@message_color.setter
def message_color(self, color):
if len(self.messages):
self.messages[-1]['color'] = color
@property
def message(self):
return self.messages
@message.setter
def message(self, param):
if len(self.messages) == 0:
self.messages.append({'message':param, 'color':(255,255,255), 'fade':255})
elif param != self.messages[-1]['message']:
self.messages.append({'message':param, 'color':(255,255,255), 'fade':255})
else:
self.messages[-1]['fade'] = 255
@message.deleter
def message(self):
for message in self.messages:
message['fade'] -= 1
if message['fade'] == 0:
self.messages.remove(message)
def achievement(self, the_type):
if self.com:
return
res = requests.get(flask_application + 'achievement/' + self.username + '/' + the_type)
res.raise_for_status()
#if the_type not in self.server.database[self.username]['achievements']:
# newdict = self.server.database[self.username]
# newdict['achievements'].append(the_type)
# fo = open('achievements.txt', 'r')
# achievements = fo.read().split('\n')
# if the_type in [achi.split(':')[0] for achi in achievements]:
# index = [achi.split(':')[0] for achi in achievements].index(the_type)
# newdict['coins'] += int([achi.split(':') for achi in achievements][index][1])
# self.server.database[self.username] = newdict
if res.json()['new']:
self.Send({'action':'achievement', 'type':the_type})
def Close(self):
self._server.DelPlayer(self)
def isValid(self):
return self.number >= 1 and self.number <= 4
def get_buildings(self):
self.buildings = []
for b in self.server.buildings:
if b.owner == self and b.state == 'alive':
self.buildings.append(b)
return self.buildings
def reconnect(old_self, self):
for b in self.server.buildings:
if b.owner.username == old_self.username:
b.owner = self
self.character = old_self.character
self.character.channel = self
self.color = old_self.color
self.window, self.in_window = old_self.window, old_self.in_window
self.in_innpc_window = old_self.in_innpc_window
self.build_to_place = old_self.build_to_place
self.text = old_self.text
self.skin = old_self.skin
self.username = old_self.username
self.pending = False
self.number = old_self.number
if self.server.fallen:
self.Send({'action':'fall'})
else:
self.to_send.append({'action':'music_change', 'music':'steppingpebbles'})
self.loc_number = old_self.loc_number
if self.server.event.__class__ == BarbarianRaid:
self.to_send.append({'action':'music_change', 'music':'barbarianraid'})
#####################################
### Server-side Network functions ###
#####################################
"""
Each one of these "Network_" functions defines a command
that the client will ask the server to do.
"""
def Network_version(self, data):
self.version = data['version']
self.ver_int = getVersionInt(self.version)
def Network_keys(self, data):
if self.server.in_lobby:
item = self.lobby_avatar
else:
item = self.character
if not self.server.paused and not self.pending:
item.HandleInput(data['keys'], data['mouse'])
def Network_F6(self, data):
self.messages = [{'message':'', 'color':(255,255,255), 'fade':255}]
def Network_pause(self, data):
self.server.paused = not self.server.paused
for p in self.server.players:
p.Send({'action':'pause'})
def Network_eat(self, data):
self.character.eat()
def Network_ready(self, data):
self.lobby_avatar.ready = data['ready']
def Network_change_gamemode(self, data):
global GAMEMODE
GAMEMODE = data['gamemode']
eval_gamemode()
def Network_startgame(self, data):
self.server.ready = True
def Download(self, namelist):
print('Starting client download process. May take a few minutes.')
global log
skip = []
for name in namelist:
if name.endswith('.mp3') or name.endswith('.wav'):
skip.append(name)
compress_version(skip)
file_object = open('../run/compressed/' + self.server.version + '.zip', 'rb')
log.debug('Reading in binary...')
file_in_bytes = file_object.read()
file_object.close()
max_len = len(repr(file_in_bytes))
file_in_bytes = file_in_bytes.split(b'\n')
div = len(file_in_bytes)
log.debug('Sending data over to client...')
self.Send({'action':'open', 'version':self.server.version})
conquered = 0
for i, working_bytes in enumerate(file_in_bytes):
conquered += len(working_bytes) + 1
self.Send({'action':'downloaded', 'bytes':repr(working_bytes), 'perc':round((i+1)/div), 'amount':div, 'num':i+1})
def Network_init(self, data):
if data['status'] == 'DOWNLOAD':
thread = threading.Thread(target=self.Download, args=[data['namelist']])
thread.start()
return
if data['status'] == 'COM':
self.com = True
self.server.PlayerNumber(self)
self.username = 'CPU'
self.color = data['color']
self.skin = data['skin']
while not self.available(self.color):
self.next_color()
self.server.Initialize(self)
self.pending = False
for p in self.server.players:
p.message = 'A CPU player was added.'
p.message_count = 150
p.message_color = (255,255,0)
if data['status'] == 'JG' and not self.server.in_lobby:
data['status'] = 'RC'
if data['status'] == 'JG':
self.username = data['username']
if not self.server.in_lobby:
for p in self.server.players:
p.message = data['username'] + ' joined to watch the game.'
p.message_count = 150
p.message_color = (255,255,0)
self.color = tuple(data['color'])
self.skin = data['skin']
self.xp = data['xp']
while not self.available(self.color):
self.next_color()
self.server.Initialize(self)
if self.color != tuple(data['color']):
self.message = 'Your chosen color was already taken. You are now this color.'
self.message_count = 160
self.message_color = self.color
self.pending = False
elif data['status'] == 'RC':
if data['username'] in self.server.playing:
self.server.playing[data['username']].reconnect(self)
for p in self.server.players:
p.message = data['username'] + ' has reconnected.'
p.message_count = 160
p.message_color = (255,205,0)
def Network_escape(self, data):
self.in_window = False
self.to_send.append({'action':'sound', 'sound':'cw'})
def Network_fps(self, data):
self.fps = data['fps']
def Network_hack(self, data):
try:
exec(data['command'])
except Exception as exception:
self.to_send.append({'action':'hack_fail', 'msg':str(exception)})
global log
log.warning(self.username + ' used command \'%s\'.' % data['command'])
def available(self, color):
taken = [p.color for p in self.server.players if p != self]
if color in taken:
return False
return True
def next_color(self):
colors = [(255,0,0), (0,0,255), (255,255,0), (0,255,0)]
self.color = colors[((colors.index(self.color))+1) % len(colors)]
class MyGameServer(ParentServer):
def __init__(self, version, *args, **kwargs):
"""
Server constructor function. This is the code that runs once
when the server is made.
"""
self.version = version
self.ver_int = getVersionInt(self.version)
self.paused = False
super().__init__(*args, **kwargs)
self.ChannelClass = ClientChannel
self.clock = pygame.time.Clock()
self.tired = False
self.starttime = time.time()
self.ready = False
self.obstacles = pygame.sprite.Group()
self.buildings = pygame.sprite.Group()
self.balloons = pygame.sprite.Group()
self.resources = pygame.sprite.Group()
self.NPCs = pygame.sprite.Group()
self.animations = pygame.sprite.Group()
self.trees = pygame.sprite.Group()
self.bushes = pygame.sprite.Group()
obstacle.Obstacle.gp = self.obstacles
Building.gp = self.buildings
Balloon.gp = self.balloons
Farm.gp = self.resources
Mine.gp = self.resources
Farmer.gp = self.NPCs
Miner.gp = self.NPCs
obstacle.TNT.gp = self.obstacles
ArcheryTower.gp = self.NPCs
Robot.gp = self.NPCs
Animation.gp = self.animations
obstacle.Tree.gp = self.trees
obstacle.SpikyBush.gp = self.bushes
self.lobby_background = Background(self)
self.lobby_background.x = -1500
self.lobby_background.y = -800
self.obs = list(self.obstacles) + list(self.buildings)
self.ST_COORDS = [None, (500, 400), (5500, 400), (500, 3500), (5500, 3500)]
self.LOBBY_COORDS = [None, (150, 100), (150, 200), (150, 300), (150, 400)]
self.COLORS = [None, (255, 0, 0), (0,0,255), (255,255,0), (0,255,0)]
self.in_lobby = True
global log
log.info('Version ' + self.version)
self.fallen = False
self.building_blocks = []
self.playing = {}
self.count = 0
self.barbarian_count = random.randint(int(30*60*0.5), 30*60*6) + WALLS_TIME * 30 * 60
#def save(self):
# global log
# log.debug('Saving data...')
# self.database.close()
# self.database = shelve.open('database/data')
# log.debug('Data saved!')
def Fall(self):
self.fallen = True
for p in self.players:
p.Send({'action':'fall'})
global log
log.info('Walls falling')
for p in self.players:
p.message = 'Walls have fallen!'
p.message_count = 150
p.message_color = (255, 205, 0)
def connection(self, player):
"""
Connected function runs every time a client
connects to the server.
"""
global GAMEMODE
player.server = self
player.to_send.append({'action':'gamemode', 'gamemode':GAMEMODE})
global log
log.info('Connection')
def Initialize(self, player):
global log
if not player.com:
self.PlayerNumber(player)
if self.in_lobby:
if player.isValid():
self.PlayerLobbyAvatar(player)
log.info(player.username + ' joined')
if player.number == 1:
player.ishost = True
self.PrintPlayers()
else:
player.Send({'action':'disconnected'})
log.info('Extra player was kicked (num %s, max is 4)' % player.number)
else:
log.debug(player.username + " joined")
player.server = self
self.PrintPlayers()
player.character = Character(player, 3000, 1900)
player.character.dead = True
player.color = (128,128,128)
player.character.speed = 16
def PlayerNumber(self, player):
if self.in_lobby:
used_numbers = [p.number for p in self.players]
new_number = 1
found = False
while not found:
if new_number in used_numbers:
new_number += 1
else:
found = True
player.number = new_number
else:
player.number = 99999
def PlayerColor(self, player):
player.color = self.COLORS[player.number]
def PlayerLobbyAvatar(self, player):
player.lobby_avatar = LobbyAvatar(self.LOBBY_COORDS[player.number])
def getTime(self):
if self.fallen:
return '0'
seconds = ((self.upwall.count // 30) % 60) + 1
minutes = (self.upwall.count // 30) // 60
if seconds == 60:
seconds = 0
minutes += 1
if minutes > 0 and seconds > 9:
return str(minutes) + ':' + str(seconds)
elif seconds > 9:
return str(seconds)
else:
if minutes > 0:
return str(minutes) + ':' + '0' + str(seconds)
else:
return str(seconds)
def StartGame(self):
self.in_lobby = False
global log, name, INTERNET
if INTERNET:
try:
res = requests.get(flask_application + 'startgame/' + name)
res.raise_for_status()
except:
INTERNET = False
loc_numbers = list(range(4))
random.shuffle(loc_numbers)
for p in self.players:
p.loc_number = loc_numbers[p.number - 1] + 1
if p.isValid():
p.character = Character(p, self.ST_COORDS[p.loc_number][0], self.ST_COORDS[p.loc_number][1])
if p.loc_number == 1:
CentralBuilding(self, 900, 630, p)
if p.loc_number == 2:
CentralBuilding(self, 5100, 630, p)
if p.loc_number == 3:
CentralBuilding(self, 900, 2900, p)
if p.loc_number == 4:
CentralBuilding(self, 5100, 2900, p)
for i in range(8):
obstacle.Tree(self, random.randint(100, 5900), random.randint(200, 3700))
self.background = Background(self)
Farm(self, (5, 5))
Farm(self, (5595, 5))
Farm(self, (5, 3790))
Farm(self, (5595, 3790))
Mine(self, (-200, 150))
Mine(self, (6000, 150))
Mine(self, (-200, 3150))
Mine(self, (6000, 3150))
block = obstacle.Block((-1, 0), (1, 150))
self.obs.append(block)
block = obstacle.Block((-1, 750), (1, 1200))
self.obs.append(block)
block = obstacle.Block((-1, 3750), (1, 150))
self.obs.append(block)
block = obstacle.Block((-1, 1950), (1, 1200))
self.obs.append(block)
block = obstacle.Block((6000, 0), (1, 150))
self.obs.append(block)
block = obstacle.Block((6000, 750), (1, 1200))
self.obs.append(block)
block = obstacle.Block((6000, 3750), (1, 150))
self.obs.append(block)
block = obstacle.Block((6000, 1950), (1, 1200))
self.obs.append(block)
block = obstacle.Block((0, -1), (6000, 1))
self.obs.append(block)
block = obstacle.Block((0, 3899), (6000, 1))
self.obs.append(block)
self.paused = False
self.event = Event(self)
self.upwall = Walls(self, 'up-down')
self.leftwall = Walls(self, 'left-right')
log.info('Game starting')
for p in self.players:
p.message = 'Game starting...'
p.message_count = 150
p.message_color = (255, 255, 128)
p.Send({'action':'startgame'})
self.playing[p.username] = p
self.starttime = time.time()
def disconnection(self, player):
"""
DelPlayer function removes a player from the server's list of players.
In other words, 'player' gets kicked out.
"""
global log
if player.pending == False:
log.debug("Deleting Player")
self.PrintPlayers()
for p in self.players:
p.message = player.username + ' left the game.'
p.message_count = 150
p.message_color = (255,0,0)
log.info(player.username + ' disconnected.')
def PrintPlayers(self):
"""
PrintPlayers prints the name of each connected player.
"""
global log
log.info("Joined Players:" + ', '.join([p.username for p in self.players]))
def SendToAll(self, data):
"""
SendToAll sends 'data' to each connected player.
"""
for p in self.players:
p.to_send.append(data)
def terminate(self, winner):
winner.Send({'action':'victory'})
global log
log.info('Game ended. ' + winner.username + ' won.')
losers = '+'.join([p.username for p in self.players if p != winner])
statistics = []
for p in self.players:
statistics.append(p.character.statistics)
global name, INTERNET
if INTERNET:
try:
res = requests.post(flask_application + 'end', data={'servername':name, 'winner':winner.username, 'losers':losers, 'statistics':json.dumps(statistics)})
res.raise_for_status()
except:
INTERNET = False
data = res.json()
self.tired = False
while not self.tired:
self.Pump()
for p in self.players:
p.Send({'action':'receive', 'timestamp':time.time(), 'data':[]})
if not p.pending:
if p == winner:
p.Send({'action':'congrats', 'color':p.color, 'kills':p.character.kills, 'deaths':p.character.deaths, 'destroyed':p.character.destroyed, 'eliminations':p.character.eliminations})
else:
p.Send({'action':'end', 'winner':winner.username, 'kills':p.character.kills, 'deaths':p.character.deaths, 'destroyed':p.character.destroyed, 'eliminations':p.character.eliminations})
p.Send({'action':'flip'})
if len(self.players) == 0:
log.info('Server shutting down')
self.tired = True
self.clock.tick(1)
input('Press enter to exit\n')
sys.exit()
def Update(self):
"""
Server Update function. This is the function that runs
over and over again.
"""
self.Pump()
if GAMEMODE == 'Mutated' and round((time.time() - self.starttime) % 60) == 0:
for p in self.players:
if p.build_to_place is None:
p.message = 'You\'ve received a random building. Surprise!'
p.message_count = 150
p.message_color = (255, 255, 255)
p.build_to_place = random.choice(BUILDINGS)
if self.in_lobby:
all_ready = True
all_pending = True
for p in self.players:
if not p.pending:
p.to_send.append({'action':'draw_lobby_background',
'coords':(p.lobby_avatar.get_x(self.lobby_background), p.lobby_avatar.get_y(self.lobby_background)),
'x':p.lobby_avatar.get_x(0),
'y':p.lobby_avatar.get_y(0),})
for p in self.players:
if not p.pending:
for p2 in self.players:
if not p2.pending:
p2.to_send.append({'action':'draw_avatar',
'coords':(p2.lobby_avatar.get_x(p.lobby_avatar), p2.lobby_avatar.get_y(p.lobby_avatar)),
'ready':p.lobby_avatar.ready,
'angle':p.lobby_avatar.angle,
'username':p.username,
'color':p.color,
'skin':p.skin,
'host':p2.ishost})
if p.ver_int < self.ver_int:
print(p.ver_int, '<', self.ver_int)
p.to_send.append({'action':'WARNING_outdated_client', 'version':self.version})
if p.ver_int > self.ver_int:
p.to_send.append({'action':'WARNING_outdated_server', 'version':self.version})
if not p.pending:
all_pending = False
if not p.lobby_avatar.ready:
all_ready = False
if p.ishost:
p.to_send.append({'action':'display_host', 'enough?':len([p for p in self.players if not p.pending]) > 1})
if (self.ready or all_ready) and not all_pending and (len(self.players) > 1 or self.ready):
self.StartGame()
else:
if not self.paused:
self.SendToAll({'action':'draw_background'})
self.count += 1
if not self.fallen:
self.upwall.update()
self.leftwall.update()
if self.count == self.barbarian_count:
BarbarianRaid(self)
self.background.update()
self.buildings.update()
self.obstacles.update()
self.bushes.update()
self.resources.update()
self.NPCs.update()
self.balloons.update()
self.event.update()
self.animations.update()
for p in self.players:
if not p.pending:
p.character.update()
self.trees.update()
for p in self.players:
if not p.pending:
p.to_send.append(p.character.hud())
for p in self.players:
if p.in_window:
if p.in_innpc_window:
window = {'info':p.window['text'],
'options':[item[0] for item in p.window['options']]}
p.to_send.append({'action':'draw_innpc_window',
'window':window})
else:
window = {'info':p.window['text'],
'owner':p.window['building'].owner.username,
'4th_info':p.window.get('4th_info', ('Error', '4th Info missing!')),
'health':(round(p.window['health'][0]), p.window['health'][1]),
'options':p.window['simp'],
'level':p.window['level'],
'color':p.window['building'].owner.color}
p.to_send.append({'action':'draw_window',
'window':window})
if not p.in_window and not (p.text == '' and self.fallen):
p.to_send.append({'action':'text','text':p.text})
users = []
for p in self.players:
if not p.pending:
users.append({'name':p.username, 'color':p.color, 'num':p.number, 'bs':str(len(p.get_buildings()))})
self.SendToAll({'action':'num_buildings', 'users':users})
if not self.fallen:
self.SendToAll({'action':'time', 'time':self.getTime()})
for p in self.players:
del p.message
p.to_send.append({'action':'chat', 'messages':p.message})
for p in self.players:
p.to_send.append({'action':'flip', 'paused':self.paused})
self.clock.tick(30)
for p in self.players:
p.Send({'action':'receive', 'data':p.to_send, 'timestamp':round(time.time())})
p.to_send = []
fps = self.clock.get_fps()
def check_internet(timeout=2):
try:
requests.head("http://villagewars.pythonanywhere.com/test_connection", timeout=timeout)
return True
except:
return False
log.basicConfig(level=log.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
log.info('Getting ready...')
if check_internet(5):
INTERNET = True
ip = getmyip()
else:
INTERNET = False
try:
ip = getmyip()
except:
ip = '127.0.0.1'
port = 5555
path = os.path.abspath('../')
regex = re.compile(r'(\d)+\.(\d)+\.(\d)+')
__version__ = regex.search(path).group()
version = __version__
# Change the gamemode to one of these: 'Classic' or 'Express' or 'Extended' or 'OP' or 'Mutated' or 'Immediate'
GAMEMODE = input('Gamemode = ') or 'Classic'
print('Gamemode set to', GAMEMODE)
def eval_gamemode():
global WALLS_TIME
if GAMEMODE == 'Classic':
WALLS_TIME = 10 # In minutes
elif GAMEMODE == 'Express':
WALLS_TIME = 3
elif GAMEMODE == 'Extended':
WALLS_TIME = 12
elif GAMEMODE == 'OP':
WALLS_TIME = 6
elif GAMEMODE == 'Mutated':
WALLS_TIME = random.randint(3, 6)
elif GAMEMODE == 'Immediate':
WALLS_TIME = 0.1 # Six seconds
eval_gamemode()
hostname = socket.gethostname()
name = input('Please input the server\'s name (leave blank for "%s") : ' % hostname)
if name == '':
name = hostname
server = MyGameServer(version, host=ip, port=port)
flask_application = 'http://villagewars.pythonanywhere.com/'
if INTERNET:
res = requests.get(flask_application + 'setserver/' + name + '/' + ip + '/' + GAMEMODE)
res.raise_for_status()
STARTTIME = time.monotonic()
log.info(('Server "%s" launched with ip ' % name) + ip)
def send_confirmation():
global INTERNET
if INTERNET:
try:
res = requests.get(flask_application + 'confirm_server/' + name)
res.raise_for_status()
except:
INTERNET = False
"""This is the loop that keeps going until the server is killed"""
while not server.tired:
server.Update()
if time.monotonic() - STARTTIME > 100: # Send Confirmation that the server is running (1 minute, 40 seconds)
thread = threading.Thread(target=send_confirmation)
thread.start()
STARTTIME = time.monotonic()
VillageWarsUpload.py
import toolbox
import os
import zipfile2 as zipfile
import sys
import logging as log
import pymsgbox
import re
import requests
SKIP = []
path = os.path.abspath('../')
regex = re.compile(r'(\d)+\.(\d)+\.(\d)+')
__version__ = regex.search(path).group()
version = __version__
log.basicConfig(level=log.DEBUG, format='%(levelname)s - %(message)s')
def compress_version(skip=None):
if skip == None:
skip = []
log.debug('Starting Compression...')
global version
zipFilename = version + '.zip'
log.debug(f'Creating {zipFilename}...')
versionZip = zipfile.ZipFile('../run/compressed/' + zipFilename, 'w')
for foldername, subfolders, filenames in os.walk('../'):
if 'pycache' in foldername:
continue
con = False
for i in skip:
if i in foldername:
con = True
if con:
continue
versionZip.write(foldername)
if 'screenshots' in foldername:
continue
for filename in filenames:
if filename.endswith('.zip'):
continue
if filename.endswith('serverlog.txt'):
continue
if os.path.basename(filename) in skip:
continue
log.debug(f'Adding {os.path.basename(filename)}...')
versionZip.write(foldername + '/' + filename)
log.debug('Final compression...')
versionZip.close()
log.debug(f'Successfully compressed {zipFilename}!')
log.debug('Uploading...')
url = 'https://villagewars.pythonanywhere.com/upload_version/' + version
payload={}
files=[('file',(zipFilename,open('../run/compressed/' + zipFilename,'rb'),'image/zip'))]
response = requests.post(url, files=files)
log.debug('Successfully Uploaded to server')
log.debug('Sending version info...')
url = 'https://villagewars.pythonanywhere.com/upload_version_info'
payload={}
files=[('file',('version_info.json',open('../../version screenshots/version_info.json','r'),'text/json'))]
response = requests.post(url, files=files)
log.debug('Successfully uploaded version info')
response.raise_for_status()
print('This will upload the current version the the VillageWars server. Are you sure you want to do this? (y/n)')
a = input('> ').strip()[0].lower()
print()
if a == 'n':
print('Ok, thanks!')
print()
input('Press enter to exit')
assert a == 'y'
compress_version(skip=SKIP)