├── .gitignore ├── .project ├── .pydevproject ├── Angler.py ├── Arborist.py ├── BaseFunctions.py ├── Builder.py ├── Buildings.py ├── Clips.py ├── DebugTools.py ├── Entities.py ├── Explorer.py ├── Farmer.py ├── FishingShip.py ├── GameEntity.py ├── Images ├── AnimationsGIMPFiles │ └── CropGrowth.xcf ├── Buildings │ ├── Building1Test.png │ ├── Dock.png │ ├── Dock_Icon.png │ ├── House.png │ ├── House_Icon.png │ ├── Inn.png │ ├── LumberYard.png │ ├── LumberYard_Icon.png │ ├── Manor.png │ ├── Manor_Icon.png │ ├── TotalImage.png │ ├── TownHall_Icon.png │ ├── UC.png │ ├── UC_Dock.png │ └── UC_House.png ├── Dial │ ├── dial.png │ └── dial_outline2.png ├── Entities │ ├── Angler.png │ ├── Arborist.png │ ├── BasicDemon.png │ ├── BigTree.png │ ├── Builder.png │ ├── BuilderLarge.png │ ├── Explorer.png │ ├── Farmer.png │ ├── FarmerLarge.png │ ├── Farmer_dig1.png │ ├── Farmer_dig2.png │ ├── Farmer_dig3.png │ ├── Farmer_dig4.png │ ├── Farmer_dig5.png │ ├── Farmer_dig6.png │ ├── Lumberjack.png │ ├── Lumberjack_chop1.png │ ├── Lumberjack_chop2.png │ ├── Lumberjack_chop3.png │ ├── Tree2.png │ ├── UsainBolt.png │ ├── Villager.png │ ├── VillagerLarge.png │ ├── VillagerTest.png │ ├── fishingship.png │ ├── info_bar.png │ └── map.png ├── New folder │ ├── Clips.png │ └── LumberjackOptimization.png ├── Screenshots │ ├── README.md │ └── Screenshot.png └── Tiles │ ├── AndrewCobble.png │ ├── AndrewCobble2.png │ ├── AndrewDeepWater.png │ ├── AndrewGrass.png │ ├── AndrewSmoothStone.png │ ├── AndrewSmoothStone2.png │ ├── AndrewWater.png │ ├── AndrewWater2.png │ ├── CarterTree.jpg │ ├── CarterTree2.jpg │ ├── Cobble.png │ ├── GrassWithCenterTree.png │ ├── GrassWithTwoTrees.png │ ├── MinecraftDarkGrass.png │ ├── MinecraftGrass.png │ ├── MinecraftSnow.png │ ├── MyGrass.png │ ├── Sand.png │ ├── Soil1.png │ ├── Soil2.png │ ├── Water.png │ ├── baby_tree.png │ └── cobble_left.png ├── LICENSE ├── Lumberjack.py ├── README.md ├── Tile.py ├── TileFuncs.py ├── UpdatingVillagerSim.py ├── VillagerSim.py ├── World.py ├── WorldGOAP.py ├── aitools ├── GoalMachine.py ├── StateMachine.py └── __init__.py ├── gametools ├── ImageFuncs.py ├── MidpointDisplacement.py ├── PertTools.py ├── VoronoiMapGen.py ├── __init__.py ├── ani.py ├── util.py └── vector2.py ├── gametools3 ├── MidpointDisplacement3.py └── __init__.py └── misctools ├── NewIcon.py └── __init__.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Screenshots 2 | Images/Screenshots/FULL_MAP_RENDER* 3 | Images/Screenshots/Minimap* 4 | Images/Screenshots/SCREENSHOT* 5 | 6 | # Created by .ignore support plugin (hsz.mobi) 7 | ### Python template 8 | # Byte-compiled / optimized / DLL files 9 | __pycache__/ 10 | *.py[cod] 11 | *$py.class 12 | 13 | # C extensions 14 | *.so 15 | 16 | # Distribution / packaging 17 | .Python 18 | env/ 19 | build/ 20 | develop-eggs/ 21 | dist/ 22 | downloads/ 23 | eggs/ 24 | .eggs/ 25 | lib/ 26 | lib64/ 27 | parts/ 28 | sdist/ 29 | var/ 30 | *.egg-info/ 31 | .installed.cfg 32 | *.egg 33 | 34 | # PyInstaller 35 | # Usually these files are written by a python script from a template 36 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 37 | *.manifest 38 | *.spec 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .coverage 48 | .coverage.* 49 | .cache 50 | nosetests.xml 51 | coverage.xml 52 | *,cover 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | 61 | # Sphinx documentation 62 | docs/_build/ 63 | 64 | # PyBuilder 65 | target/ 66 | 67 | 68 | ### Example user template template 69 | ### Example user template 70 | 71 | # IntelliJ project files 72 | .idea 73 | *.iml 74 | out 75 | gen 76 | 77 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | VillagerSim 4 | 5 | 6 | 7 | 8 | 9 | org.python.pydev.PyDevBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.python.pydev.pythonNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.pydevproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | Default 4 | python 2.7 5 | 6 | -------------------------------------------------------------------------------- /Angler.py: -------------------------------------------------------------------------------- 1 | from aitools.StateMachine import * 2 | from Entities import * 3 | from GameEntity import * 4 | from gametools.vector2 import Vector2 5 | from gametools.ImageFuncs import * 6 | from gametools.ani import * 7 | import BaseFunctions 8 | import math 9 | import pygame 10 | import random 11 | import TileFuncs 12 | from World import * 13 | #TODO: Clean up imports and add docstrings 14 | 15 | class Angler(GameEntity): 16 | 17 | def __init__(self, world, image_string): 18 | # Initializing the class 19 | GameEntity.__init__(self, world, "Angler", "Entities/"+image_string) 20 | 21 | # Creating the states 22 | fishing_state = Fishing(self) 23 | exploring_state = Searching(self) 24 | delivering_state = Delivering(self) 25 | 26 | # Adding states to the brain 27 | self.brain.add_state(fishing_state) 28 | self.brain.add_state(exploring_state) 29 | self.brain.add_state(delivering_state) 30 | 31 | self.max_speed = 80.0 * (1.0 / 60.0) 32 | self.speed = self.max_speed 33 | self.base_speed = self.speed 34 | self.view_range = 2 35 | self.fish = 0 36 | 37 | self.worldSize = world.world_size 38 | self.TileSize = self.world.tile_size 39 | 40 | # animation variables 41 | self.animation = Ani(9, 10) 42 | self.pic = pygame.image.load("Images/Entities/map.png") 43 | self.img_func = ImageFuncs(18, 17,self.pic) 44 | self.sprites = self.img_func.get_images(9,0,2) 45 | self.hit = 0 46 | self.update() 47 | 48 | def update(self): 49 | self.image = self.sprites[self.animation.get_frame()] 50 | self.image.set_colorkey((255,0,255)) 51 | if self.animation.finished: 52 | self.hit += 1 53 | self.animation.finished = False 54 | 55 | 56 | class Fishing(State): 57 | 58 | def __init__(self, angler): 59 | 60 | State.__init__(self, "Fishing") 61 | self.angler = angler 62 | 63 | def check_conditions(self): 64 | 65 | if self.angler.location.get_distance_to(self.angler.destination) <= self.angler.max_speed: 66 | self.angler.destination = Vector2(self.angler.location) 67 | self.angler.update() 68 | 69 | if self.angler.fish == 1: 70 | return "Delivering" 71 | 72 | def do_actions(self): 73 | if self.angler.location == self.angler.destination and self.angler.hit >= 4: 74 | # TODO: Why is this checking if the tile is fishable if it has been fishing there? 75 | 76 | for tile_location in TileFuncs.get_vnn_array(self.angler.world, self.angler.location, 2): 77 | if TileFuncs.get_tile(self.angler.world, tile_location).fishable: 78 | self.angler.hit = 0 79 | self.angler.fish = 1 80 | 81 | def entry_actions(self): 82 | BaseFunctions.random_dest(self.angler) 83 | 84 | 85 | class Searching(State): 86 | 87 | def __init__(self, angler): 88 | State.__init__(self, "Searching") 89 | self.angler = angler 90 | 91 | def entry_actions(self): 92 | BaseFunctions.random_dest(self.angler) 93 | 94 | def do_actions(self): 95 | pass 96 | 97 | def check_conditions(self): 98 | if self.angler.location.get_distance_to(self.angler.destination) < self.angler.max_speed: 99 | location_array = TileFuncs.get_vnn_array(self.angler.world,(self.angler.location), self.angler.view_range) 100 | 101 | for location in location_array: 102 | # TODO: This will make the angler go into the water, change this to go to the nearest walkable tile. 103 | test_tile = TileFuncs.get_tile(self.angler.world, location) 104 | if test_tile.__class__.__name__ == "WaterTile": 105 | 106 | self.angler.destination = location.copy() 107 | return "Fishing" 108 | 109 | BaseFunctions.random_dest(self.angler) 110 | 111 | def exit_actions(self): 112 | pass 113 | 114 | class Delivering(State): 115 | 116 | def __init__(self, angler): 117 | State.__init__(self, "Delivering") 118 | self.angler = angler 119 | 120 | def entry_actions(self): 121 | #TODO: Make dropoff point dynamic (e.g. it's own building) 122 | 123 | self.angler.destination = Vector2(self.angler.world.w/2, self.angler.world.h/2) 124 | 125 | def do_actions(self): 126 | pass 127 | 128 | def check_conditions(self): 129 | 130 | if self.angler.location.get_distance_to(self.angler.destination) < 15: 131 | self.angler.world.fish += self.angler.fish 132 | self.angler.fish = 0 133 | return "Searching" 134 | 135 | def exit_actions(self): 136 | pass 137 | -------------------------------------------------------------------------------- /Arborist.py: -------------------------------------------------------------------------------- 1 | from aitools.StateMachine import * 2 | from Entities import * 3 | from GameEntity import * 4 | from gametools.vector2 import Vector2 5 | from gametools.ImageFuncs import * 6 | from gametools.ani import * 7 | import math 8 | import pygame 9 | import random 10 | import TileFuncs 11 | import BaseFunctions 12 | 13 | class Arborist(GameEntity): 14 | 15 | def __init__(self, world, image_string): 16 | # Initializing the class 17 | GameEntity.__init__(self, world, "Arborist", "Entities/"+image_string) 18 | 19 | # Creating the states 20 | planting_state = Arborist_Planting(self) 21 | 22 | # Adding states to the brain 23 | self.brain.add_state(planting_state) 24 | 25 | self.max_speed = 80.0 * (1.0 / 60.0) 26 | self.speed = self.max_speed 27 | self.base_speed = self.speed 28 | 29 | self.worldSize = world.world_size 30 | self.TileSize = self.world.tile_size 31 | 32 | # animation variables 33 | self.animation = Ani(6,10) 34 | self.pic = pygame.image.load("Images/Entities/map.png") 35 | self.img_func = ImageFuncs(18, 17,self.pic) 36 | self.sprites = self.img_func.get_images(6,0,0) 37 | self.hit = 0 38 | self.update() 39 | 40 | def update(self): 41 | # Updates image every 10 cycles and adds 1 to the 4 hit dig 42 | self.image = self.sprites[self.animation.get_frame()] 43 | self.image.set_colorkey((255,0,255)) 44 | if self.animation.finished == True: 45 | self.hit += 1 46 | self.animation.finished = False 47 | 48 | 49 | class Arborist_Planting(State): 50 | 51 | def __init__(self, Arborist): 52 | 53 | State.__init__(self, "Planting") 54 | self.arborist = Arborist 55 | 56 | def check_conditions(self): 57 | 58 | if self.arborist.location.get_distance_to(self.arborist.destination) < 15: 59 | self.arborist.destination = Vector2(self.arborist.location) 60 | self.arborist.update() 61 | 62 | def do_actions(self): 63 | 64 | if self.arborist.location == self.arborist.destination and self.arborist.hit >= 4 and TileFuncs.get_tile( 65 | self.arborist.world,self.arborist.location).plantable == 1: 66 | self.plant_seed() 67 | 68 | if self.arborist.location == self.arborist.destination and self.arborist.hit != 4 and TileFuncs.get_tile( 69 | self.arborist.world, self.arborist.location).plantable != 1: 70 | BaseFunctions.random_dest(self.arborist) 71 | 72 | def plant_seed(self): 73 | # Function for planting trees 74 | 75 | # Test to see if the tile the arborist is on is a tile that a tree can be planted on 76 | if TileFuncs.get_tile(self.arborist.world,self.arborist.location).plantable == 1: 77 | self.arborist.hit = 0 78 | self.arborist.update() 79 | old_tile = TileFuncs.get_tile(self.arborist.world,Vector2(self.arborist.location)) 80 | 81 | darkness = pygame.Surface((32, 32)) 82 | darkness.set_alpha(old_tile.darkness) 83 | 84 | new_tile = Tile.Baby_Tree(self.arborist.world, "GrassWithCenterTree") 85 | 86 | new_tile.darkness = old_tile.darkness 87 | 88 | new_tile.location = TileFuncs.get_tile_pos(self.arborist.world,self.arborist.destination)*32 89 | new_tile.rect.topleft = new_tile.location 90 | new_tile.color = old_tile.color 91 | 92 | self.arborist.world.tile_array[int(new_tile.location.y/32)][int(new_tile.location.x/32)] = new_tile 93 | self.arborist.world.world_surface.blit(new_tile.img, new_tile.location) 94 | self.arborist.world.world_surface.blit(darkness, new_tile.location) 95 | 96 | # Goes to a random destination no matter what 97 | self.arborist.hit = 0 98 | BaseFunctions.random_dest(self.arborist) 99 | 100 | def entry_actions(self): 101 | BaseFunctions.random_dest(self.arborist) 102 | -------------------------------------------------------------------------------- /BaseFunctions.py: -------------------------------------------------------------------------------- 1 | import random 2 | import math 3 | from gametools.vector2 import Vector2 4 | import TileFuncs 5 | 6 | DEBUG = False 7 | 8 | def random_dest(entity, recurse=False, r_num=0, r_max=6): 9 | # Function for going to a random destination 10 | if recurse: 11 | entity.orientation += 30 12 | else: 13 | entity.orientation += random.randint(-30, 30) 14 | angle = math.radians(entity.orientation) 15 | distance = random.randint(50, 100) 16 | possible_dest = Vector2(entity.location.x + math.cos(angle) * distance, entity.location.y + math.sin(angle) * distance) 17 | 18 | # If the destination will go off the map, it is NOT a valid move under any circumstances. 19 | bad_spot = False 20 | if (0 > possible_dest.x > entity.world.world_size[0] or \ 21 | 0 > possible_dest.y > entity.world.world_size[1]): 22 | bad_spot = True 23 | if DEBUG: 24 | "BAD SPOT IS TRUE" 25 | 26 | walk = TileFuncs.get_tile(entity.world, possible_dest).walkable == entity.land_based 27 | depth_max = r_num >= r_max 28 | 29 | if ((not walk and not depth_max) or bad_spot): 30 | random_dest(entity, True, r_num+1, r_max) 31 | return 32 | 33 | else: 34 | entity.destination = possible_dest 35 | 36 | if DEBUG: 37 | print("Current Tile: " + TileFuncs.get_tile(entity.world, entity.location).__class__.__name__) 38 | print("Destination Tile: " + TileFuncs.get_tile(entity.world, entity.destination).__class__.__name__) 39 | print("r_num: %d" % r_num) 40 | print("walk: ", walk) 41 | print("") 42 | if bad_spot: print("BAD SPOT, WTF") 43 | -------------------------------------------------------------------------------- /Builder.py: -------------------------------------------------------------------------------- 1 | from aitools.StateMachine import * 2 | from World import * 3 | from GameEntity import * 4 | from gametools.vector2 import Vector2 5 | 6 | from Buildings import * 7 | 8 | from random import * 9 | 10 | import pygame 11 | 12 | 13 | class Builder(GameEntity): 14 | def __init__(self, world, image, rest): 15 | GameEntity.__init__(self, world, "Builder", image) 16 | 17 | self.current_build = None 18 | 19 | self.speed = 100.0 20 | 21 | self.building_state = Builder_Building(self) 22 | self.Idle_state = Builder_Idle(self) 23 | self.Finding_state = Builder_Finding(self) 24 | 25 | self.brain.add_state(self.building_state) 26 | self.brain.add_state(self.Idle_state) 27 | self.brain.add_state(self.Finding_state) 28 | 29 | self.IdleLocation = rest.location.copy() 30 | 31 | 32 | class Builder_Building(State): 33 | def __init__(self, Builder): 34 | State.__init__(self, "Building") 35 | self.Builder = Builder 36 | 37 | def check_conditions(self): 38 | if self.building_complete >= 5.0: 39 | self.Builder.target.create() 40 | 41 | self.Builder.world.BuildingQueue.remove(self.Builder.target) 42 | return "Finding" 43 | 44 | def do_actions(self): 45 | self.building_complete += self.Builder.tp 46 | 47 | def entry_actions(self): 48 | self.Builder.destination = self.Builder.location.copy() 49 | self.building_complete = 0.0 50 | 51 | 52 | class Builder_Finding(State): # Finding a suitable place to build. 53 | """If: 54 | Lumber Yard - In the woods not near anything else 55 | Docks - Edge of the water, decently distanced from others 56 | House - Somewhere in the town area 57 | Manor - near top of the map or maybe replaces a house. 58 | """ 59 | 60 | def __init__(self, Builder): 61 | State.__init__(self, "Finding") 62 | self.Builder = Builder 63 | 64 | def check_conditions(self): 65 | if len(self.Builder.world.BuildingQueue) == 0: 66 | return "Idle" 67 | 68 | if self.Builder.location.get_distance_to(self.Builder.destination) < 2: 69 | return "Building" 70 | 71 | def do_actions(self): 72 | pass 73 | 74 | def entry_actions(self): 75 | try: 76 | self.Builder.destination = self.Builder.world.BuildingQueue[0].location.copy() 77 | self.Builder.target = self.Builder.world.BuildingQueue[0] 78 | 79 | except IndexError: 80 | pass 81 | 82 | 83 | class Builder_Idle(State): 84 | def __init__(self, Builder): 85 | State.__init__(self, "Idle") 86 | self.Builder = Builder 87 | 88 | def entry_actions(self): 89 | self.Builder.destination = self.Builder.IdleLocation 90 | 91 | def check_conditions(self): 92 | if len(self.Builder.world.BuildingQueue) >= 1: 93 | return "Finding" 94 | -------------------------------------------------------------------------------- /Buildings.py: -------------------------------------------------------------------------------- 1 | from aitools.StateMachine import * 2 | import GameEntity 3 | from gametools.vector2 import Vector2 4 | import glob 5 | 6 | import ImageFuncs 7 | import pygame 8 | 9 | 10 | class Building(GameEntity.GameEntity): 11 | def __init(self, world, name, image_string="Inn"): 12 | GameEntity.__init__(self, world, name, "Buildings/"+image_string) 13 | 14 | self.image_funcs = ImageFuncs(32, 32, pygame.image.load("Images/Buildings/TotalImage.png")) 15 | self.tile_x, self.tile_y = pos 16 | self.cost = 100 17 | get_images(name) 18 | 19 | self.can_drop_food = False 20 | self.can_drop_wood = False 21 | 22 | 23 | class LumberYard(Building): 24 | def __init__(self, world, image_string="LumberYard"): 25 | Building.__init__(self, world, "Lumber Yard", image_string) 26 | 27 | self.image = self.image_funcs.get_irregular_image(2, 2, 2, 2) 28 | self.Held = 0 29 | self.HeldMax = 50 30 | self.cost = 100 31 | 32 | self.world.MAXwood += self.HeldMax 33 | self.can_drop_wood = True 34 | 35 | 36 | class Dock(Building): 37 | 38 | def __init__(self, world, image_string="Dock"): 39 | Building.__init__(self, world, "Dock", image_string) 40 | 41 | self.image = self.image_funcs.get_irregular_image(2, 2, 2, 0) 42 | 43 | self.Held = 0 44 | self.HeldMax = 25 45 | self.cost = 150 46 | 47 | self.can_drop_food = True 48 | 49 | self.world.MAXfood += self.HeldMax 50 | 51 | class House(Building): 52 | def __init__(self, world, image_string="House"): 53 | Building.__init__(self, world, "House", image_string) 54 | 55 | self.supports = 5 56 | self.cost = 30 57 | 58 | self.world.MAXpopulation += self.supports 59 | 60 | 61 | class Manor(Building): 62 | def __init__(self, world, image_string="Manor"): 63 | Building.__init__(self, world, "Manor", image_string) 64 | 65 | self.image = self.image_funcs.get_irregular_image(2, 2, 2, 4) 66 | 67 | self.supports = 15 68 | self.cost = 100 69 | 70 | self.world.MAXpopulation += self.supports 71 | 72 | class TownCenter(Building): 73 | def __init__(self, world, image_string="Manor"): 74 | Building.__init__(self, world, "Town Center", image_string) 75 | 76 | self.image = self.image_funcs.get_irregular_image(2, 2, 2, 6) 77 | 78 | self.can_drop_food = True 79 | self.can_drop_wood = True 80 | 81 | self.supports = 15 82 | self.cost = 500 83 | 84 | self.world.MAXpopulation += self.supports 85 | self.world.MAXWood += 50 86 | self.world.MAXFood += 50 87 | 88 | 89 | class UnderConstruction(Building): 90 | def __init__(self, world, image_string, will_be): 91 | Building.__init__(self, world, "Under Construction", image_string) 92 | self.will_be = will_be 93 | self.ttb = 30.0 94 | self.max_ttb = 30.0 95 | 96 | def create(self): 97 | self.world.add_built(self.will_be, self.location) 98 | self.world.remove_entity(self) 99 | 100 | 101 | class StoreShed(Building): 102 | 103 | def __init__(self, world, image_string): 104 | Building.__init__(self, world, "Store Shed", image_string) 105 | -------------------------------------------------------------------------------- /Clips.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | dialol = pygame.image.load("Images/Dial/dial_outline2.png") 4 | dial = pygame.image.load("Images/Dial/dial.png") 5 | dialol.set_colorkey((255, 0, 255)) 6 | dial.set_colorkey((255, 0, 255)) 7 | 8 | buildings = ["House", "LumberYard", "Dock", "Manor", "Town Center"] 9 | 10 | 11 | class Clips(object): 12 | """ 13 | ______________________ 14 | | | 15 | | | 16 | | | 17 | | | 18 | | | 19 | | | 20 | | _____| 21 | | |MINI-| 22 | | |MAP | 23 | ---------------------- 24 | """ 25 | 26 | def __init__(self, world, screen_size): 27 | self.size = screen_size 28 | self.world = world 29 | 30 | # The minimap is 1/4 the size of the screen in each dimension (1/16 total size) 31 | self.minimap_size = int(self.size[0] / 4), int(self.size[1] / 4) 32 | 33 | # TODO: Is this necessary? 34 | self.minimap = pygame.transform.scale( 35 | self.world.minimap_img, 36 | self.minimap_size) 37 | 38 | # Ratio between the size of the tile array and the minimap size 39 | self.a = self.world.w / float(self.minimap_size[0]) 40 | self.b = self.world.h / float(self.minimap_size[1]) 41 | 42 | # Not quite sure what this does 43 | self.rect_view_w = (self.size[0] / self.a) - ((self.size[0] / self.a) / 5) 44 | self.rect_view_h = self.size[1] / self.b 45 | 46 | self.minimap_rect = pygame.Rect(self.size[0] - self.minimap_size[0], self.size[1] - self.minimap_size[1], 47 | self.minimap_size[0], self.minimap_size[1]) 48 | 49 | def render(self, surface): 50 | 51 | rect_view_pos = ( 52 | (-1 * self.world.world_position.x / self.a) + self.size[0] - self.minimap_size[0] + ((self.size[0] / 5) / self.a), 53 | (-1 * self.world.world_position.y / self.b) + self.size[1] - self.minimap_size[1]) 54 | 55 | rect_view = ( 56 | rect_view_pos, 57 | (self.rect_view_w, 58 | self.rect_view_h)) 59 | 60 | self.world.render(surface) 61 | # self.update_dial(surface, tp) 62 | 63 | # Draw minimap below here ------------------ 64 | surface.set_clip(self.minimap_rect) 65 | 66 | # Drawing the actual minimap 67 | surface.blit(self.minimap, self.minimap_rect) 68 | 69 | # Draw the white rectangle displaying where the user is located 70 | pygame.draw.rect(surface, (255, 255, 255), rect_view, 1) 71 | 72 | # Draw a black border 73 | pygame.draw.rect(surface, (0, 0, 0), self.minimap_rect, 2) 74 | 75 | surface.set_clip(None) 76 | # Draw minimap above here -------------------- 77 | 78 | def update_dial(self, surface, tp): # Dial goes below here 79 | box = (self.size[0] - 55, self.size[1] / 50 - 40) 80 | boxtest = pygame.Rect((box[0] - 20, box[1] + 80), (50, 50)) 81 | oldCenter = boxtest.center 82 | rotateddial = pygame.transform.rotate(dial, self.world.clock_degree) 83 | rotRect = rotateddial.get_rect() 84 | rotRect.center = oldCenter 85 | self.world.clock_degree += tp 86 | if self.world.clock_degree >= 360.0: 87 | self.world.clock_degree = 0.0 88 | 89 | surface.blit(rotateddial, rotRect) 90 | surface.blit(dialol, (box[0] - 44, box[1] + 55)) -------------------------------------------------------------------------------- /DebugTools.py: -------------------------------------------------------------------------------- 1 | import TileFuncs 2 | 3 | def print_surrounding_tiles(world, print_type="Name"): 4 | tile_range = 2 5 | location_array = TileFuncs.get_vnn_array(world, world.entities[0].location, tile_range) 6 | 7 | if print_type=="Name": 8 | tile_list = tile_array_from_location(world, location_array) 9 | else: 10 | tile_list = location_array 11 | # print "Length of tile_list: %d"%len(tile_list) 12 | 13 | print(tile_list[0]) 14 | print(tile_list[1], tile_list[2], tile_list[3]) 15 | print(tile_list[4]) 16 | print("") 17 | 18 | def tile_array_from_location(world, array): 19 | return_array = [] 20 | for i in array: 21 | return_array.append(TileFuncs.get_tile(world, i).name) 22 | 23 | return return_array 24 | 25 | def print_location_tile(world, location): 26 | print(TileFuncs.get_tile(world, location).__class__.__name__) 27 | -------------------------------------------------------------------------------- /Entities.py: -------------------------------------------------------------------------------- 1 | from aitools.StateMachine import * 2 | from World import * 3 | from GameEntity import * 4 | from gametools.vector2 import * 5 | 6 | from random import * 7 | 8 | 9 | class Tree(GameEntity): 10 | def __init__(self, world, image): 11 | GameEntity.__init__(self, world, "Tree", image) 12 | 13 | 14 | class Sapling(GameEntity): 15 | def __init__(self, world, image): 16 | GameEntity.__init__(self, world, "Sapling", image) 17 | growing_state = Growing(self) 18 | self.brain.add_state(growing_state) 19 | self.ttg = 30.0 20 | 21 | 22 | class Growing(State): 23 | def __init__(self, Sapling): 24 | State.__init__(self, "Growing") 25 | self.Sapling = Sapling 26 | 27 | def check_conditions(self): 28 | if self.Sapling.ttg <= 0: 29 | new_tree = Tree(self.Sapling.world, tree_image) 30 | new_tree.location = self.Sapling.location.copy() 31 | self.Sapling.world.add_entity(new_tree) 32 | self.Sapling.world.remove_entity(self.Sapling) 33 | 34 | def do_actions(self): 35 | self.Sapling.ttg -= self.Sapling.tp 36 | # print self.Sapling.ttg 37 | -------------------------------------------------------------------------------- /Explorer.py: -------------------------------------------------------------------------------- 1 | """The explorer is a villager driven to the find the amazing by thier 2 | unwaivering curiosity for what is unknown. These will seek new land 3 | and features to help advance the civilization, though may at times 4 | pursure knowledge at other costs. 5 | 6 | Also this class was primarily developed to track down movement bugs.""" 7 | 8 | import aitools.StateMachine 9 | 10 | import GameEntity 11 | import BaseFunctions 12 | 13 | class Explorer(GameEntity.GameEntity): 14 | """See file doctring for the description.""" 15 | 16 | 17 | def __init__(self, world, image_string): 18 | """Basic initialization for the class.""" 19 | 20 | GameEntity.GameEntity.__init__(self, world, "Explorer", "Entities/"+image_string) 21 | 22 | self.speed = 80.0 * (1.0 / 60.0) 23 | self.base_speed = self.speed 24 | self.view_range = 8 25 | 26 | self.exploring_state = Exploring(self) 27 | 28 | self.brain.add_state(self.exploring_state) 29 | 30 | self.worldSize = world.world_size 31 | self.TileSize = self.world.tile_size 32 | 33 | class Exploring(aitools.StateMachine.State): 34 | """The primary function of the explorer, to search for places previously 35 | unvisited or unfound. Eventually the explorer should keep track of 36 | and prioritize places it hasn't visited.""" 37 | 38 | def __init__(self, this_explorer): 39 | aitools.StateMachine.State.__init__(self, "Exploring") 40 | self.explorer = this_explorer 41 | 42 | def entry_actions(self): 43 | """When the explorer starts exploring (enters exploring state).""" 44 | BaseFunctions.random_dest(self.explorer) 45 | 46 | def do_actions(self): 47 | """What should the explorer do while it is exploring""" 48 | pass 49 | 50 | def check_conditions(self): 51 | """Check if the explorer should still be exploring""" 52 | if self.explorer.location.get_distance_to(self.explorer.destination) <= self.explorer.speed: 53 | BaseFunctions.random_dest(self.explorer) 54 | 55 | def exit_actions(self): 56 | """What the explorer does as it stops exploring""" 57 | pass 58 | -------------------------------------------------------------------------------- /Farmer.py: -------------------------------------------------------------------------------- 1 | """This class is going to be tasked with planting and harvesting crops. This 2 | class used to plant trees, however this has been moved to Arborist (which 3 | is the name of someone who takes care of trees you pleb).""" 4 | 5 | import aitools.StateMachine 6 | from Entities import * 7 | from GameEntity import * 8 | from gametools.vector2 import Vector2 9 | from gametools.ImageFuncs import * 10 | from gametools.ani import * 11 | import math 12 | import pygame 13 | import random 14 | import TileFuncs 15 | import BaseFunctions 16 | 17 | class Farmer(GameEntity): 18 | """The main class for Farmer. See above for the description""" 19 | 20 | def __init__(self, world, image_string): 21 | """Basic initialization""" 22 | 23 | # Initializing the class 24 | GameEntity.__init__(self, world, "Farmer", "Entities/"+image_string) 25 | 26 | # Creating the states 27 | tilling_state = Farmer_Tilling(self) 28 | 29 | # Adding states to the brain 30 | self.brain.add_state(tilling_state) 31 | 32 | self.max_speed = 80.0 * (1.0 / 60.0) 33 | self.speed = self.max_speed 34 | self.base_speed = self.speed 35 | 36 | self.worldSize = world.world_size 37 | self.TileSize = self.world.tile_size 38 | 39 | class Farmer_Tilling(aitools.StateMachine.State): 40 | 41 | def __init__(self, farmer): 42 | aitools.StateMachine.State.__init__(self, "Tilling") 43 | self.farmer = farmer 44 | 45 | def entry_actions(self): 46 | BaseFunctions.random_dest(self.farmer) 47 | 48 | def do_actions(self): 49 | current_tile = TileFuncs.get_tile(self.farmer.world, self.farmer.location) 50 | if current_tile.tillable: 51 | darkness = pygame.Surface((self.farmer.TileSize, self.farmer.TileSize)) 52 | darkness.set_alpha(current_tile.darkness) 53 | 54 | new_tile = Tile.SoilTile(self.farmer.world, "Soil2") 55 | new_tile.darkness = darkness 56 | 57 | new_tile.location = current_tile.location 58 | new_tile.rect.topleft = new_tile.location 59 | new_tile.color = current_tile.color # TODO: Figure out what this does. 60 | 61 | self.farmer.world.tile_array[int(new_tile.location.y / 32)][int(new_tile.location.x / 32)] = new_tile 62 | self.farmer.world.world_surface.blit(new_tile.img, new_tile.location) 63 | self.farmer.world.world_surface.blit(darkness, new_tile.location) 64 | # TODO: Update the minimap 65 | 66 | BaseFunctions.random_dest(self.farmer) 67 | 68 | elif self.farmer.location.get_distance_to(self.farmer.destination) < self.farmer.speed: 69 | BaseFunctions.random_dest(self.farmer) 70 | 71 | def check_conditions(self): 72 | pass 73 | 74 | def exit_actions(self): 75 | pass 76 | 77 | -------------------------------------------------------------------------------- /FishingShip.py: -------------------------------------------------------------------------------- 1 | import GameEntity 2 | import aitools.StateMachine as StateMachine 3 | import math, random 4 | from gametools.vector2 import Vector2 5 | import BaseFunctions 6 | 7 | 8 | class FishingShip(GameEntity.GameEntity): 9 | 10 | def __init__(self, world, img): 11 | GameEntity.GameEntity.__init__(self, world, "Fishing Ship", img) 12 | 13 | self.speed = 50.0 * (1.0 / 60.0) 14 | self.view_range = 5 15 | 16 | self.searching_state = Searching(self) 17 | 18 | self.brain.add_state(self.searching_state) 19 | 20 | class Searching(StateMachine.State): 21 | """Looking for something to gather""" 22 | 23 | def __init__(self, fishing_ship): 24 | 25 | StateMachine.State.__init__(self, "Searching") 26 | self.fishing_ship = fishing_ship 27 | 28 | def check_conditions(self): 29 | if self.fishing_ship.location.get_distance_to(self.fishing_ship.destination) < self.fishing_ship.speed: 30 | BaseFunctions.random_dest(self.fishing_ship) 31 | 32 | def do_actions(self): 33 | pass 34 | 35 | def entry_actions(self): 36 | BaseFunctions.random_dest() 37 | 38 | def exit_actions(self): 39 | pass 40 | 41 | class Gathering(StateMachine.State): 42 | """In the state of gathering""" 43 | 44 | def __init__(self, fishing_ship): 45 | 46 | StateMachine.State.__init__(self, "Gathering") 47 | self.fishing_ship = fishing_ship 48 | 49 | def check_conditions(self): 50 | pass 51 | 52 | def do_actions(self): 53 | pass 54 | 55 | def entry_actions(self): 56 | pass 57 | 58 | def exit_actions(self): 59 | pass 60 | 61 | class Returning(StateMachine.State): 62 | """Returning what is gathered to the dock""" 63 | 64 | def __init__(self, fishing_ship): 65 | StateMachine.State.__init__(self, "Returning") 66 | self.fishing_ship = fishing_ship 67 | 68 | def check_conditions(self): 69 | pass 70 | 71 | def do_actions(self): 72 | pass 73 | 74 | def entry_actions(self): 75 | pass 76 | 77 | def exit_actions(self): 78 | pass 79 | -------------------------------------------------------------------------------- /GameEntity.py: -------------------------------------------------------------------------------- 1 | from World import * 2 | from aitools.StateMachine import * 3 | from gametools.vector2 import * 4 | import TileFuncs 5 | import pygame 6 | from pygame.locals import * 7 | 8 | # TODO: Clean and add doctrings 9 | 10 | 11 | class GameEntity(object): 12 | def __init__(self, world, name, image_string): 13 | 14 | self.world = world 15 | self.name = name 16 | 17 | self.image = pygame.image.load("Images/"+image_string+".png") 18 | self.orientation = 0 19 | 20 | try: 21 | self.image.set_colorkey((255, 0, 255)) 22 | except AttributeError: 23 | pass 24 | 25 | self.location = Vector2(0, 0) 26 | self.world_location = Vector2(0, 0) 27 | self.destination = Vector2(0, 0) 28 | 29 | self.speed = 0. 30 | 31 | self.land_based = True 32 | self.base_speed = self.speed 33 | 34 | self.food = 70 35 | self.water = 70 36 | self.energy = 70 37 | self.active_info = False 38 | 39 | self.brain = StateMachine() 40 | 41 | self.id = 0 42 | 43 | self.tp = 1.0 44 | 45 | def render(self, surface): 46 | x, y = self.world_location 47 | w, h = self.image.get_size() 48 | pos = (x - (w / 2), y - (h / 2)) 49 | surface.blit(self.image, pos) 50 | 51 | def check_speed(self): 52 | if TileFuncs.get_tile(self.world, self.location).name in ["AndrewSmoothStone", "MinecraftSnow"]: 53 | self.speed = 0.5 * self.base_speed 54 | else: 55 | self.speed = self.base_speed 56 | 57 | def process(self, time_passed): 58 | self.brain.think() 59 | self.world_location = self.location + self.world.world_position 60 | 61 | 62 | self.check_speed() 63 | 64 | if self.speed > 0. and self.location != self.destination: 65 | vec_to_destination = self.destination - self.location 66 | distance_to_destination = vec_to_destination.get_length() 67 | heading = vec_to_destination.get_normalized() 68 | travel_distance = min(distance_to_destination, self.speed) 69 | self.location += travel_distance * heading * self.speed 70 | -------------------------------------------------------------------------------- /Images/AnimationsGIMPFiles/CropGrowth.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/AnimationsGIMPFiles/CropGrowth.xcf -------------------------------------------------------------------------------- /Images/Buildings/Building1Test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Buildings/Building1Test.png -------------------------------------------------------------------------------- /Images/Buildings/Dock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Buildings/Dock.png -------------------------------------------------------------------------------- /Images/Buildings/Dock_Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Buildings/Dock_Icon.png -------------------------------------------------------------------------------- /Images/Buildings/House.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Buildings/House.png -------------------------------------------------------------------------------- /Images/Buildings/House_Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Buildings/House_Icon.png -------------------------------------------------------------------------------- /Images/Buildings/Inn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Buildings/Inn.png -------------------------------------------------------------------------------- /Images/Buildings/LumberYard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Buildings/LumberYard.png -------------------------------------------------------------------------------- /Images/Buildings/LumberYard_Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Buildings/LumberYard_Icon.png -------------------------------------------------------------------------------- /Images/Buildings/Manor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Buildings/Manor.png -------------------------------------------------------------------------------- /Images/Buildings/Manor_Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Buildings/Manor_Icon.png -------------------------------------------------------------------------------- /Images/Buildings/TotalImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Buildings/TotalImage.png -------------------------------------------------------------------------------- /Images/Buildings/TownHall_Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Buildings/TownHall_Icon.png -------------------------------------------------------------------------------- /Images/Buildings/UC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Buildings/UC.png -------------------------------------------------------------------------------- /Images/Buildings/UC_Dock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Buildings/UC_Dock.png -------------------------------------------------------------------------------- /Images/Buildings/UC_House.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Buildings/UC_House.png -------------------------------------------------------------------------------- /Images/Dial/dial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Dial/dial.png -------------------------------------------------------------------------------- /Images/Dial/dial_outline2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Dial/dial_outline2.png -------------------------------------------------------------------------------- /Images/Entities/Angler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Angler.png -------------------------------------------------------------------------------- /Images/Entities/Arborist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Arborist.png -------------------------------------------------------------------------------- /Images/Entities/BasicDemon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/BasicDemon.png -------------------------------------------------------------------------------- /Images/Entities/BigTree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/BigTree.png -------------------------------------------------------------------------------- /Images/Entities/Builder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Builder.png -------------------------------------------------------------------------------- /Images/Entities/BuilderLarge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/BuilderLarge.png -------------------------------------------------------------------------------- /Images/Entities/Explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Explorer.png -------------------------------------------------------------------------------- /Images/Entities/Farmer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Farmer.png -------------------------------------------------------------------------------- /Images/Entities/FarmerLarge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/FarmerLarge.png -------------------------------------------------------------------------------- /Images/Entities/Farmer_dig1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Farmer_dig1.png -------------------------------------------------------------------------------- /Images/Entities/Farmer_dig2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Farmer_dig2.png -------------------------------------------------------------------------------- /Images/Entities/Farmer_dig3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Farmer_dig3.png -------------------------------------------------------------------------------- /Images/Entities/Farmer_dig4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Farmer_dig4.png -------------------------------------------------------------------------------- /Images/Entities/Farmer_dig5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Farmer_dig5.png -------------------------------------------------------------------------------- /Images/Entities/Farmer_dig6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Farmer_dig6.png -------------------------------------------------------------------------------- /Images/Entities/Lumberjack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Lumberjack.png -------------------------------------------------------------------------------- /Images/Entities/Lumberjack_chop1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Lumberjack_chop1.png -------------------------------------------------------------------------------- /Images/Entities/Lumberjack_chop2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Lumberjack_chop2.png -------------------------------------------------------------------------------- /Images/Entities/Lumberjack_chop3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Lumberjack_chop3.png -------------------------------------------------------------------------------- /Images/Entities/Tree2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Tree2.png -------------------------------------------------------------------------------- /Images/Entities/UsainBolt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/UsainBolt.png -------------------------------------------------------------------------------- /Images/Entities/Villager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/Villager.png -------------------------------------------------------------------------------- /Images/Entities/VillagerLarge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/VillagerLarge.png -------------------------------------------------------------------------------- /Images/Entities/VillagerTest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/VillagerTest.png -------------------------------------------------------------------------------- /Images/Entities/fishingship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/fishingship.png -------------------------------------------------------------------------------- /Images/Entities/info_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/info_bar.png -------------------------------------------------------------------------------- /Images/Entities/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Entities/map.png -------------------------------------------------------------------------------- /Images/New folder/Clips.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/New folder/Clips.png -------------------------------------------------------------------------------- /Images/New folder/LumberjackOptimization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/New folder/LumberjackOptimization.png -------------------------------------------------------------------------------- /Images/Screenshots/README.md: -------------------------------------------------------------------------------- 1 | Folder for Screenshot 2 | --------------------- 3 | -------------------------------------------------------------------------------- /Images/Screenshots/Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Screenshots/Screenshot.png -------------------------------------------------------------------------------- /Images/Tiles/AndrewCobble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/AndrewCobble.png -------------------------------------------------------------------------------- /Images/Tiles/AndrewCobble2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/AndrewCobble2.png -------------------------------------------------------------------------------- /Images/Tiles/AndrewDeepWater.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/AndrewDeepWater.png -------------------------------------------------------------------------------- /Images/Tiles/AndrewGrass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/AndrewGrass.png -------------------------------------------------------------------------------- /Images/Tiles/AndrewSmoothStone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/AndrewSmoothStone.png -------------------------------------------------------------------------------- /Images/Tiles/AndrewSmoothStone2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/AndrewSmoothStone2.png -------------------------------------------------------------------------------- /Images/Tiles/AndrewWater.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/AndrewWater.png -------------------------------------------------------------------------------- /Images/Tiles/AndrewWater2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/AndrewWater2.png -------------------------------------------------------------------------------- /Images/Tiles/CarterTree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/CarterTree.jpg -------------------------------------------------------------------------------- /Images/Tiles/CarterTree2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/CarterTree2.jpg -------------------------------------------------------------------------------- /Images/Tiles/Cobble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/Cobble.png -------------------------------------------------------------------------------- /Images/Tiles/GrassWithCenterTree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/GrassWithCenterTree.png -------------------------------------------------------------------------------- /Images/Tiles/GrassWithTwoTrees.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/GrassWithTwoTrees.png -------------------------------------------------------------------------------- /Images/Tiles/MinecraftDarkGrass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/MinecraftDarkGrass.png -------------------------------------------------------------------------------- /Images/Tiles/MinecraftGrass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/MinecraftGrass.png -------------------------------------------------------------------------------- /Images/Tiles/MinecraftSnow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/MinecraftSnow.png -------------------------------------------------------------------------------- /Images/Tiles/MyGrass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/MyGrass.png -------------------------------------------------------------------------------- /Images/Tiles/Sand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/Sand.png -------------------------------------------------------------------------------- /Images/Tiles/Soil1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/Soil1.png -------------------------------------------------------------------------------- /Images/Tiles/Soil2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/Soil2.png -------------------------------------------------------------------------------- /Images/Tiles/Water.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/Water.png -------------------------------------------------------------------------------- /Images/Tiles/baby_tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/baby_tree.png -------------------------------------------------------------------------------- /Images/Tiles/cobble_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/najarvis/villager-sim/55fca98611bbbd927f8e6981a8e68040b03fd5e3/Images/Tiles/cobble_left.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /Lumberjack.py: -------------------------------------------------------------------------------- 1 | from aitools.StateMachine import * 2 | from Entities import * 3 | from GameEntity import * 4 | from gametools.vector2 import Vector2 5 | from gametools.ImageFuncs import * 6 | from gametools.ani import * 7 | import Tile 8 | import math 9 | import pygame 10 | import random 11 | import TileFuncs 12 | from World import * 13 | import BaseFunctions 14 | 15 | NoTreeImg = pygame.image.load("Images/Tiles/MinecraftGrass.png") 16 | 17 | class Lumberjack(GameEntity): 18 | 19 | def __init__(self, world, image_string): 20 | # Initializing the class 21 | GameEntity.__init__(self, world, "Lumberjack", "Entities/"+image_string) 22 | 23 | self.speed = 100.0 * (1.0 / 60.0) 24 | self.base_speed = self.speed 25 | self.view_range = 6 26 | 27 | # Creating the states 28 | self.searching_state = Searching(self) 29 | self.chopping_state = Chopping(self) 30 | self.delivering_state = Delivering(self) 31 | 32 | # Adding states to the brain 33 | self.brain.add_state(self.searching_state) 34 | self.brain.add_state(self.chopping_state) 35 | self.brain.add_state(self.delivering_state) 36 | 37 | self.worldSize = world.world_size 38 | self.TileSize = self.world.tile_size 39 | 40 | # animation variables 41 | self.animation = Ani(5,10) 42 | self.pic = pygame.image.load("Images/Entities/map.png") 43 | self.img_func = ImageFuncs(18, 17,self.pic) 44 | self.sprites = self.img_func.get_images(5,0,1) 45 | self.hit = 0 46 | self.update() 47 | 48 | def update(self): 49 | # Updates image every 10 cycles and adds 1 to the 4 hit dig 50 | self.image = self.sprites[self.animation.get_frame()] 51 | self.image.set_colorkey((255,0,255)) 52 | if self.animation.finished == True: 53 | self.hit += 1 54 | self.animation.finished = False 55 | 56 | 57 | class Searching(State): 58 | """This state will be used to have the Lumberjack looking for 59 | trees to cut, It needs to be fast enough to have AT LEAST 20 Lumberjacks 60 | with little to no framerate loss. 61 | 62 | Perhaps it could be used to find a clump of trees. and then the Lumberjack 63 | wouldn't just wander around aimlessly searching for trees even though it 64 | saw some when it was just at another tree""" 65 | 66 | def __init__(self, Lumberjack): 67 | State.__init__(self, "Searching") 68 | self.lumberjack = Lumberjack 69 | 70 | def entry_actions(self): 71 | BaseFunctions.random_dest(self.lumberjack) 72 | 73 | def do_actions(self): 74 | pass 75 | 76 | def check_conditions(self): 77 | if self.lumberjack.location.get_distance_to(self.lumberjack.destination) < 15: 78 | location_array = TileFuncs.get_vnn_array(self.lumberjack.world,(self.lumberjack.location), self.lumberjack.view_range) 79 | 80 | for location in location_array: 81 | test_tile = TileFuncs.get_tile(self.lumberjack.world,location) 82 | if test_tile.name == "GrassWithCenterTree": 83 | self.lumberjack.Tree_tile = test_tile 84 | self.lumberjack.tree_id = test_tile.id 85 | 86 | self.lumberjack.destination = location.copy() 87 | return "Chopping" 88 | 89 | BaseFunctions.random_dest(self.lumberjack) 90 | 91 | def exit_actions(self): 92 | pass 93 | 94 | 95 | class Chopping(State): 96 | def __init__(self, Lumberjack): 97 | State.__init__(self, "Chopping") 98 | self.lumberjack = Lumberjack 99 | 100 | def entry_actions(self): 101 | pass 102 | 103 | def do_actions(self): 104 | pass 105 | 106 | def check_conditions(self): 107 | check = TileFuncs.get_tile(self.lumberjack.world,Vector2(self.lumberjack.location)) 108 | if self.lumberjack.location.get_distance_to(self.lumberjack.destination) < 15: 109 | self.lumberjack.destination = Vector2(self.lumberjack.location) 110 | 111 | if check.name != "GrassWithCenterTree": 112 | self.lumberjack.hit = 0 113 | self.lumberjack.update() 114 | return "Searching" 115 | 116 | self.lumberjack.update() 117 | 118 | if self.lumberjack.hit >= 4: 119 | self.lumberjack.destination = Vector2(self.lumberjack.location) 120 | self.lumberjack.update() 121 | 122 | old_tile = TileFuncs.get_tile(self.lumberjack.world,Vector2(self.lumberjack.location)) 123 | 124 | darkness = pygame.Surface((32, 32)) 125 | darkness.set_alpha(old_tile.darkness) 126 | 127 | new_tile = Tile.TreePlantedTile(self.lumberjack.world, "MinecraftGrass") 128 | 129 | new_tile.darkness = old_tile.darkness 130 | 131 | new_tile.location = TileFuncs.get_tile_pos(self.lumberjack.world,self.lumberjack.destination)*32 132 | new_tile.rect.topleft = new_tile.location 133 | new_tile.color = old_tile.color 134 | 135 | self.lumberjack.world.tile_array[int(new_tile.location.y/32)][int(new_tile.location.x/32)] = new_tile 136 | self.lumberjack.world.world_surface.blit(new_tile.img, new_tile.location) 137 | self.lumberjack.world.world_surface.blit(darkness, new_tile.location) 138 | 139 | self.lumberjack.hit = 0 140 | 141 | # del self.lumberjack.world.TreeLocations[str(self.lumberjack.tree_id)] 142 | return "Delivering" 143 | 144 | def exit_actions(self): 145 | pass 146 | 147 | 148 | class Delivering(State): 149 | """This state will be used solely to deliver wood from wherever the Lumberjack 150 | got the wood to the closest Lumber yard. maybe all the lumber yards could 151 | be stored in a dictionary similar to trees, that would be much faster""" 152 | 153 | def __init__(self, Lumberjack): 154 | State.__init__(self, "Delivering") 155 | self.lumberjack = Lumberjack 156 | 157 | def entry_actions(self): 158 | self.lumberjack.destination = Vector2(self.lumberjack.world.w/2,self.lumberjack.world.h/2) 159 | 160 | def do_actions(self): 161 | pass 162 | 163 | def check_conditions(self): 164 | 165 | # if self.lumberjack.world.wood >= self.lumberjack.world.MAXwood: 166 | # return "IDLE" 167 | 168 | if self.lumberjack.location.get_distance_to(self.lumberjack.destination) < 15: 169 | self.lumberjack.world.wood += 5 170 | return "Searching" 171 | 172 | def exit_actions(self): 173 | pass 174 | 175 | 176 | class IDLE(State): 177 | def __init__(self, Lumberjack): 178 | State.__init__(self, "Delivering") 179 | self.lumberjack = Lumberjack 180 | 181 | def entry_actions(self): 182 | pass 183 | 184 | def do_actions(self): 185 | pass 186 | 187 | def check_conditions(self): 188 | pass 189 | 190 | def exit_actions(self): 191 | pass 192 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Villager-Sim 2 | ============ 3 | 4 | A project we have been working on for a while. The end goal is to create a 5 | civilization that can grow and explore on it's own though artificial intelligence 6 | by setting goals for itself, learning what it needs to do to accomplish those goals. 7 | 8 | Start 9 | ----- 10 | 11 | To run this you must Install PyGame - http://www.pygame.org/download.shtml 12 | 13 | Start with ```python UpdatingVillagerSim.py``` 14 | 15 | Additional start flags: 16 | 17 | ```python UpdatingVillagerSim.py [fullscreen] [world size] [hard shadow]``` 18 | 19 | ```fullscreen``` is a boolean value (0 / 1) that controls if the game will start fullscreen or not. WARNING: If running on linux, if the program crashes while in fullscreen mode it is difficult to close. 20 | 21 | ```world size``` is an integer (preferably an order of magnitude of 2) that controls the dimensions of the tile map of the game world. The game world is a square so you only need to supply the value of one side (e.g. 64). 22 | 23 | ```hard shadow``` is a boolean value (0 / 1) that controls if the shadow from elevation is rendered on the game world or just the minimap. 24 | 25 | Note, you cannot just select ```hard shadow``` without the other two, nor ```world size``` without ```fullscreen```. 26 | 27 | Licence 28 | ------- 29 | 30 | GNU GENERAL PUBLIC LICENSE Version 2 31 | -------------------------------------------------------------------------------- /Tile.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | from gametools.vector2 import Vector2 4 | 5 | 6 | class Tile(object): 7 | def __init__(self, world, tile_name="NULL"): 8 | self.world = world 9 | self.name = tile_name 10 | self.img = pygame.image.load("Images/Tiles/"+tile_name+".png").convert() 11 | self.location = Vector2(0, 0) 12 | self.walkable = False 13 | self.fishable = False 14 | self.plantable = False 15 | self.tillable = False 16 | self.crop_plantable = False 17 | self.buildable = False 18 | self.buildable_w = False 19 | self.darkness = 0 20 | 21 | self.id = 0 22 | self.rect = pygame.Rect((0, 0), self.img.get_size()) 23 | 24 | def render(self, screen): 25 | screen.blit(self.img, self.location) 26 | 27 | 28 | class GrassTile(Tile): 29 | def __init__(self, world, tile_name): 30 | Tile.__init__(self, world, tile_name) 31 | self.walkable = True 32 | self.buildable = True 33 | self.plantable = True 34 | self.tillable = True 35 | 36 | class WaterTile(Tile): 37 | def __init__(self, world, tile_name): 38 | Tile.__init__(self, world, tile_name) 39 | self.buildable_w = True 40 | self.fishable = True 41 | 42 | class DeepWaterTile(Tile): 43 | def __init__(self, world, tile_name): 44 | Tile.__init__(self, world, tile_name) 45 | self.buildable_w = True 46 | 47 | class SmoothStoneTile(Tile): 48 | def __init__(self, world, tile_name): 49 | Tile.__init__(self, world, tile_name) 50 | self.walkable = True 51 | self.buildable = True 52 | 53 | class CobblestoneTile(Tile): 54 | def __init__(self, world, tile_name): 55 | Tile.__init__(self, world, tile_name) 56 | self.walkable = True 57 | self.buildable = True 58 | 59 | class DirtTile(Tile): 60 | def __init__(self, world, tile_name): 61 | Tile.__init__(self, world, tile_name) 62 | self.walkable = True 63 | self.buildable = True 64 | self.tillable = True 65 | 66 | class BeachTile(Tile): 67 | def __init__(self, world, tile_name): 68 | Tile.__init__(self, world, tile_name) 69 | self.walkable = True 70 | self.buildable = True 71 | 72 | class Baby_Tree(Tile): 73 | def __init__(self, world, tile_name): 74 | Tile.__init__(self, world, tile_name) 75 | self.walkable = True 76 | 77 | class TreePlantedTile(Tile): 78 | def __init__(self, world, tile_name): 79 | Tile.__init__(self, world, tile_name) 80 | self.walkable = True 81 | self.Taken = False 82 | 83 | class SnowTile(Tile): 84 | def __init__(self, world, tile_name): 85 | Tile.__init__(self, world, tile_name) 86 | 87 | 88 | class BuildingTile(Tile): 89 | def __init__(self, world, tile_name): 90 | Tile.__init__(self, world, tile_name) 91 | self.walkable = True 92 | 93 | class SoilTile(Tile): 94 | def __init__(self, world, tile_name): 95 | Tile.__init__(self, world, tile_name) 96 | self.walkable = True 97 | self.crop_plantable = True 98 | -------------------------------------------------------------------------------- /TileFuncs.py: -------------------------------------------------------------------------------- 1 | from gametools import vector2 2 | import Tile 3 | import math 4 | 5 | def get_tile(world, location): 6 | tile = get_tile_pos(world, location) 7 | try: 8 | return world.tile_array[int(tile.y)][int(tile.x)] 9 | except IndexError: 10 | return Tile.Tile(world, "Sand") 11 | 12 | def get_tile_pos(world, location): 13 | return vector2.Vector2(int(location.x) >> 5, int(location.y) >> 5) 14 | 15 | def get_entity(world,location, radius = 20): 16 | for i in world.entities.items(): 17 | ent_location = i[1].world_location 18 | if ((ent_location.x - location.x)**2 + (ent_location.y - location.y)**2) < radius**2: 19 | return i 20 | # print "no ents" 21 | 22 | def get_tile_array(world, start_pos, dimensions): 23 | dimensions = (int(dimensions[0]), int(dimensions[1])) 24 | 25 | start_tile = get_tile_pos(world,start_pos) 26 | 27 | array = [[None for i in xrange((dimensions[0] * 2) + 1)] 28 | for a in xrange((dimensions[1] * 2) + 1)] 29 | 30 | for i in xrange((dimensions[0] * 2) + 1): 31 | for a in xrange((dimensions[1] * 2) + 1): 32 | if start_tile.x + i < 0 or start_tile.y + a < 0: 33 | continue 34 | 35 | else: 36 | try: 37 | array[a][i] = world.tile_array[int((start_tile.y + a) - 1)][int((start_tile.x + i) - 1)] 38 | except IndexError: 39 | #print a, i, start_tile 40 | raise IndexError 41 | return array 42 | 43 | def get_vnn_array(world, location, r): 44 | """ Stands for Von Neumann Neighborhood. 45 | Simply returns a neighborhood of locations based 46 | on the initial location and range r""" 47 | 48 | return_array = [] 49 | 50 | """ 51 | range: 3 52 | num rows: 5 (number of rows is equal to (2 * r) - 1 53 | 0 * 1 left column is row_number 54 | 1 * * * 3 right column is num_in_row 55 | 2 * * * * * 5 56 | 3 * * * 3 middle is illustration of what is looks like 57 | 4 * 1 num_in_row is just how many spots are looked at in the current row. 58 | """ 59 | 60 | for row_number in range((2 * r) - 1): 61 | if row_number >= r: 62 | num_in_row = (2 * row_number) - (4 * (row_number - r + 1) - 1) 63 | else: 64 | num_in_row = (2 * row_number) + 1 65 | 66 | for cell in range(num_in_row): 67 | 68 | """ 69 | the y_offset goes from -(r - 1) to +(r - 1) (not affected by the inner loop) 70 | 71 | the x_offset goes from -math.floor(num_in_row / 2.0) to +math.floor(num_in_row / 2.0) 72 | 73 | 0 0 1 | (0, -2) x, y offset pairs of a range 3 vnn array 74 | 1 0 1 2 3 | (-1, -1) (0, -1) (1, -1) 75 | 2 0 1 2 3 4 5 | (-2, 0) (-1, 0 ) (0, 0 ) (1, 0 ) (2, 0) left column is row_number 76 | 3 0 1 2 3 | (-1, 1 ) (0, 1 ) (1, 1 ) right column is num_in_row 77 | 4 0 1 | (0, 2 ) middle is cell number 78 | """ 79 | 80 | tile_size = world.tile_size 81 | x_offset = cell - math.floor(num_in_row / 2.0) 82 | y_offset = row_number - (r - 1) 83 | 84 | new_location = vector2.Vector2(location.x + (x_offset * tile_size), location.y + (y_offset * tile_size)) 85 | return_array.append(new_location) 86 | 87 | return return_array 88 | -------------------------------------------------------------------------------- /UpdatingVillagerSim.py: -------------------------------------------------------------------------------- 1 | #!python2 2 | 3 | """This will basically be a rewrite of the original file, 4 | but this time with a focus on clean code and commenting.""" 5 | 6 | import sys 7 | import pygame 8 | import gametools.vector2 9 | import TileFuncs 10 | import World 11 | import DebugTools 12 | 13 | def run(fullscreen, world_size=64): 14 | """The main function to run the program. 15 | 16 | Args: 17 | fullscreen: Boolean value that determines if the program is 18 | in fullscreen mode. 19 | 20 | world_size: Integer (power of 2) value that determines the 21 | dimensions of the game world in terms of tiles. 22 | 23 | Returns: 24 | None 25 | """ 26 | 27 | pygame.init() 28 | screen_size = (1280, 720) 29 | if fullscreen: 30 | screen_size = pygame.display.list_modes()[0] 31 | if screen_size[0] > 1920: 32 | screen_size = (1920, 1080) 33 | screen = pygame.display.set_mode(screen_size, 34 | pygame.FULLSCREEN | pygame.HWSURFACE) 35 | else: 36 | screen = pygame.display.set_mode(screen_size, 0) 37 | 38 | game_world = World.World((world_size, world_size), screen_size) 39 | 40 | pygame.display.set_caption("Villager Sim") 41 | 42 | # Tick the clock once to avoid one huge tick when the game starts 43 | game_world.clock.tick() 44 | 45 | pause = False 46 | 47 | done = False 48 | while not done: 49 | 50 | # Cap the game at 60 fps 51 | time_passed_seconds = game_world.clock.tick(60) / 1000.0 52 | pos = gametools.vector2.Vector2(*pygame.mouse.get_pos()) 53 | 54 | for event in pygame.event.get(): 55 | 56 | # Close button clicked 57 | if event.type == pygame.QUIT: 58 | done = True 59 | 60 | elif event.type == pygame.KEYDOWN: 61 | 62 | # Escape key pressed 63 | if event.key == pygame.K_ESCAPE: 64 | done = True 65 | 66 | elif event.key == pygame.K_SPACE: 67 | pause = not pause 68 | 69 | elif event.key == pygame.K_F3: 70 | pygame.image.save(game_world.world_surface, "FullScreenshot.png") 71 | 72 | elif event.type == pygame.MOUSEBUTTONDOWN: 73 | if event.button == 3: 74 | entity = TileFuncs.get_entity(game_world, pos) 75 | if entity is not None: 76 | # Toggle the entity info 77 | entity[1].active_info = not entity[1].active_info 78 | 79 | if pygame.mouse.get_pressed()[0]: 80 | # check to see if the user is clicking on the minimap and update position accordingly 81 | game_world.check_minimap_update(pos) 82 | 83 | # Process everything in the game world 84 | if not pause: 85 | game_world.process(time_passed_seconds) 86 | 87 | # Clear the screen, then draw the world onto it 88 | screen.fill((0, 0, 0)) 89 | game_world.render_all(screen) 90 | 91 | # Update the screen 92 | pygame.display.update() 93 | 94 | pygame.quit() 95 | 96 | if __name__ == "__main__": 97 | if len(sys.argv) == 2: 98 | run(bool(int(sys.argv[1]))) 99 | elif len(sys.argv) >= 3: 100 | run(bool(int(sys.argv[1])), int(sys.argv[2])) 101 | else: 102 | run(True, 128) 103 | -------------------------------------------------------------------------------- /VillagerSim.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding:utf-8 -*- 3 | 4 | """VillagerSim, a project aimed at creating an artificial intelligence, capable of exploring an island""" 5 | 6 | import pygame 7 | 8 | pygame.init() 9 | 10 | from gametools.vector2 import Vector2 11 | from World import World 12 | from datetime import datetime 13 | from Clips import Clips 14 | 15 | 16 | def run(): 17 | """Simply runs the game.""" 18 | 19 | 20 | font = pygame.font.SysFont("Terminal", 20) 21 | bool_full = False 22 | screen_size = (1280, 720) 23 | 24 | screen_width, screen_height = screen_size 25 | 26 | side_size = screen_width / 5.0 27 | 28 | if bool_full: 29 | screen = pygame.display.set_mode((1600, 900), pygame.FULLSCREEN | pygame.HWSURFACE, 32) 30 | else: 31 | screen = pygame.display.set_mode(screen_size, 0, 32) 32 | 33 | # For the selection 34 | draw = False 35 | held = False 36 | 37 | s_size = 128 38 | size = (s_size, s_size) 39 | 40 | seed = None 41 | 42 | world = World(size, font, seed, screen_size) 43 | 44 | # These are all loaded here to be used in the main file. 45 | # TODO: Move these somewhere else 46 | placing_lumberyard_img = pygame.image.load("Images/Buildings/Dark_LumberYard.png").convert() 47 | placing_lumberyard_img.set_colorkey((255, 0, 255)) 48 | 49 | placing_house_img = pygame.image.load("Images/Buildings/Dark_House.png").convert() 50 | placing_house_img.set_colorkey((255, 0, 255)) 51 | 52 | placing_dock_img = pygame.image.load("Images/Buildings/Dark_Dock.png").convert() 53 | placing_dock_img.set_colorkey((255, 0, 255)) 54 | 55 | placing_manor_img = pygame.image.load("Images/Buildings/Dark_Manor.png").convert() 56 | placing_manor_img.set_colorkey((255, 0, 255)) 57 | 58 | bad_lumberyard_img = pygame.image.load("Images/Buildings/Red_LumberYard.png").convert() 59 | bad_lumberyard_img.set_colorkey((255, 0, 255)) 60 | 61 | world.clipper = Clips(world, (screen_width, screen_height)) 62 | selected_building = "LumberYard" 63 | selected_img = pygame.image.load( 64 | "Images/Buildings/Dark_LumberYard.png").convert() 65 | selected_img.set_colorkey((255, 0, 255)) 66 | 67 | world.clock.tick() 68 | done = False 69 | while not done: 70 | 71 | time_passed_seconds = world.clock.tick_busy_loop(60) / 1000. 72 | pos = Vector2(*pygame.mouse.get_pos()) 73 | 74 | for event in pygame.event.get(): 75 | if event.type == pygame.QUIT: 76 | done = True 77 | 78 | if event.type == pygame.MOUSEBUTTONDOWN: 79 | if (pos.x > world.clipper.minimap_rect.x and pos.y > 80 | world.clipper.minimap_rect.y): 81 | pass 82 | else: 83 | if event.button == 1 and selected_building is None: 84 | """This determines what icon you clicked on in the building selector""" 85 | held = True 86 | start = Vector2(*pygame.mouse.get_pos()) 87 | draw = True 88 | if (pos.x < world.clipper.side.w) and (pos.y < world.clipper.side.top_rect.h): 89 | for tile_list in world.clipper.side.tiles: 90 | for tile in tile_list: 91 | if tile is None: 92 | continue 93 | 94 | if tile.rect.collidepoint((pos.x, pos.y)): 95 | if tile.selected: 96 | tile.selected = False 97 | else: 98 | tile.selected = True 99 | 100 | selected_building = tile.rep 101 | world.clipper.side.update(tile) 102 | 103 | else: 104 | world.clipper.side.update() 105 | 106 | elif event.button == 1 and selected_building is not None: 107 | if pos.x > world.clipper.side.w: 108 | world.add_building(selected_building, pos) 109 | if world.test_buildable(selected_building, 0, pos): 110 | selected_building = None 111 | world.clipper.side.update() 112 | 113 | if event.button == 3: 114 | selected_building = None 115 | 116 | if event.type == pygame.MOUSEBUTTONUP: 117 | draw = False 118 | held = False 119 | 120 | if event.type == pygame.KEYDOWN: 121 | if event.key == pygame.K_F2 or event.key == pygame.K_F3 or \ 122 | event.key == pygame.K_F4: 123 | str1 = str(datetime.now()) 124 | str1 = str1.split(".") 125 | str2 = str1[0] + str1[1] 126 | str2 = str2.split(":") 127 | str1 = "" 128 | for i in str2: 129 | str1 += i 130 | 131 | if event.key == pygame.K_F2: 132 | pygame.image.save(screen, "Images/Screenshots/SCREENSHOT%s.png" %str1) 133 | 134 | elif event.key == pygame.K_F3: 135 | pygame.image.save(world.clipper.minimap, "Images/Screenshots/MinimapSCREENSHOT%s.png" %str1) 136 | 137 | elif event.key == pygame.K_F4: 138 | pygame.image.save(world.full_surface, "Images/Screenshots/FULL_MAP_RENDER%s.png" %str1) 139 | 140 | if event.key == pygame.K_n: 141 | world.new_world() 142 | 143 | if event.key == pygame.K_ESCAPE: 144 | done = True 145 | 146 | # ------------------Keys Below-------------------------------------- 147 | pressed_keys = pygame.key.get_pressed() 148 | if pressed_keys[pygame.K_ESCAPE]: # quits the game 149 | done = True 150 | 151 | if pressed_keys[pygame.K_d]: # Fast-forward function 152 | world.clock_degree += 5 153 | 154 | # Test to see what the first entity's current state is 155 | if pressed_keys[pygame.K_l]: 156 | print world.entities[0].brain.active_state 157 | 158 | # --------------Keys Above---------------------------------------- 159 | # --------------Mouse Below--------------------------------------- 160 | 161 | if int(pos.x) <= 15: 162 | if not bool_full: 163 | pygame.mouse.set_pos((15, pos.y)) 164 | world.background_pos.x += 500 * time_passed_seconds 165 | if world.background_pos.x > side_size: 166 | world.background_pos.x = side_size 167 | 168 | elif int(pos.x) >= screen_width - 16: 169 | if not bool_full: 170 | pygame.mouse.set_pos((screen_width - 16, pos.y)) 171 | world.background_pos.x -= 500 * time_passed_seconds 172 | 173 | if world.background_pos.x < -1 * (world.w - screen_width): 174 | world.background_pos.x = -1 * (world.w - screen_width) 175 | 176 | # print world.background_pos.x 177 | 178 | if int(pos.y) <= 15: 179 | if not bool_full: 180 | pygame.mouse.set_pos((pos.x, 15)) 181 | world.background_pos.y += 500 * time_passed_seconds 182 | 183 | if world.background_pos.y > 0: 184 | world.background_pos.y = 0 185 | 186 | elif int(pos.y) >= screen_height - 16: 187 | 188 | if not bool_full: 189 | pygame.mouse.set_pos((pos.x, screen_height - 16)) 190 | 191 | world.background_pos.y -= 500 * time_passed_seconds 192 | 193 | if world.background_pos.y < -1 * (world.h - screen_height): 194 | world.background_pos.y = -1 * (world.h - screen_height) 195 | 196 | if pygame.mouse.get_pressed()[0]: 197 | if pos.x > world.clipper.minimap_rect.x and pos.y > world.clipper.minimap_rect.y: 198 | """ If the player clicked on the mini map, 199 | go to that location with the view centered on the event position""" 200 | draw = False 201 | if not held: 202 | world.background_pos.x = (-1 * (pos.x - world.clipper.minimap_rect.x) * world.clipper.a) + ( 203 | world.clipper.rect_view_w * world.clipper.a) / 2 204 | 205 | world.background_pos.y = (-1 * (pos.y - world.clipper.minimap_rect.y) * world.clipper.b) + ( 206 | world.clipper.rect_view_h * world.clipper.b) / 2 207 | 208 | # --------------Mouse Above--------------------------------------- 209 | # --------------Process below------------------------------------- 210 | 211 | world.process(time_passed_seconds) 212 | 213 | if selected_building == "House": 214 | selected_img = placing_house_img 215 | elif selected_building == "LumberYard": 216 | selected_img = placing_lumberyard_img 217 | elif selected_building == "Dock": 218 | selected_img = placing_dock_img 219 | elif selected_building == "Manor": 220 | selected_img = placing_manor_img 221 | 222 | # --------------Process above------------------------------------- 223 | # --------------Render Below------------------------ 224 | 225 | screen.fill((0, 0, 0)) 226 | world.render_all(screen, time_passed_seconds, pos) 227 | 228 | #world.grow_trees(world.baby_tree_locations) 229 | 230 | if selected_building is not None: 231 | if (pos.x > world.clipper.minimap_rect.x and pos.y > world.clipper.minimap_rect.y) or ( 232 | pos.x < world.clipper.side.w + 32): 233 | pass 234 | else: 235 | if not world.test_buildable(selected_building, 0, pos): 236 | selected_img = bad_lumberyard_img 237 | blit_pos = world.get_tile_pos(pos - world.background_pos) * 32 238 | screen.blit(selected_img, ((blit_pos.x - (selected_img.get_width() - 32)) + world.background_pos.x, 239 | (blit_pos.y - (selected_img.get_height() - 32)) + world.background_pos.y)) 240 | 241 | # ------------Render above---------------------------- 242 | # This is for selecting------------- 243 | if draw and selected_building is None: 244 | current_mouse_pos = Vector2(*pygame.mouse.get_pos()) 245 | 246 | lst = world.get_tile_array(start, ((current_mouse_pos.x - start.x) / 32, (current_mouse_pos.x - start.x) / 32)) 247 | for i in lst: 248 | for j in i: 249 | j.selected = 1 250 | 251 | select_surface = pygame.Surface((abs(current_mouse_pos.x - start.x), abs(current_mouse_pos.y - start.y))) 252 | select_surface.set_alpha(25) 253 | select_surface.fill((255, 255, 255)) 254 | 255 | if current_mouse_pos.x - \ 256 | start.x <= 0 and current_mouse_pos.y < start.y and current_mouse_pos.x > start.x: 257 | newa = (current_mouse_pos.x - (current_mouse_pos.x - start.x), current_mouse_pos.y) 258 | screen.blit(select_surface, (newa)) 259 | if current_mouse_pos.x - \ 260 | start.x <= 0 and current_mouse_pos.y > start.y and current_mouse_pos.x < start.x: 261 | newa = (current_mouse_pos.x, current_mouse_pos.y - (current_mouse_pos.y - start.y)) 262 | screen.blit(select_surface, (newa)) 263 | if current_mouse_pos.x - \ 264 | start.x > 0 and current_mouse_pos.y - start.y > 0: 265 | screen.blit(select_surface, (start)) 266 | if current_mouse_pos.x - \ 267 | start.x < 0 and current_mouse_pos.y - start.y < 0: 268 | screen.blit(select_surface, (current_mouse_pos)) 269 | pygame.draw.rect( 270 | screen, (255, 255, 255), (start, (current_mouse_pos.x - start.x, current_mouse_pos.y - start.y)), 1) 271 | # Selecting Above------------------ 272 | 273 | # --------------Render Above------------------------ 274 | 275 | pygame.display.flip() 276 | pygame.display.set_caption("VillagerSim") 277 | 278 | pygame.quit() 279 | 280 | if __name__ == "__main__": 281 | run() 282 | -------------------------------------------------------------------------------- /World.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pygame 3 | from gametools import vector2, VoronoiMapGen, MidpointDisplacement, PertTools 4 | import math 5 | import Tile 6 | import Clips 7 | import Farmer 8 | import Lumberjack 9 | import Angler 10 | import Explorer 11 | import Arborist 12 | 13 | class World(object): 14 | """This class holds everything in the game. It also 15 | updates and renders it all each frame.""" 16 | 17 | def __init__(self, tile_dimensions, screen_size): 18 | """Basic initialization. 19 | 20 | Args: 21 | tile_dimensions: The dimensions of the world in terms 22 | of tiles. default is 128x128 tiles. 23 | 24 | screen_size: The size of the window, this is used for scaling 25 | (mostly of the minimap). 26 | 27 | Returns: 28 | None 29 | """ 30 | 31 | self.tile_size = 32 32 | self.w, self.h = self.world_size = (tile_dimensions[0] * self.tile_size, tile_dimensions[1] * self.tile_size) 33 | self.world_position = vector2.Vector2(-self.w / 2, -self.h / 2) 34 | 35 | self.clock = pygame.time.Clock() 36 | 37 | # Unused variables 38 | self.wood = 0 39 | self.fish = 0 40 | 41 | # Entities 42 | self.entities = {} 43 | self.buildings = {} 44 | self.entity_id = 0 45 | self.building_id = 0 46 | 47 | self.new_world(tile_dimensions) 48 | self.clipper = Clips.Clips(self, screen_size) 49 | 50 | # TODO (wazzup771@gmail.com | Nick Wayne): Not sure if these belong here either 51 | self.info_bar = pygame.image.load("Images/Entities/info_bar.png").convert() 52 | self.info_bar.set_colorkey((255, 0, 255)) 53 | self.f_high = (50, 200, 50) 54 | self.f_low = (255, 0, 0) 55 | self.w_high = (0, 0, 255) 56 | self.w_low = (76, 70, 50) 57 | self.e_high = (0, 255, 0) 58 | self.e_low = (50, 50, 0) 59 | 60 | def new_world(self, array_size): 61 | """Creates a new world (including all of the entities) 62 | 63 | Args: 64 | array_size: The size of the tile array, same as tile_dimensions 65 | in the constructor. 66 | 67 | Returns: 68 | None 69 | """ 70 | 71 | map_width, map_height = array_size 72 | map_generator = VoronoiMapGen.mapGen() 73 | 74 | # midpoint_generator = MidpointDisplacement.MidpointDisplacement() 75 | # mid_map = PertTools.scale_array(midpoint_generator.normalize(midpoint_generator.NewMidDis(int(math.log(map_width, 2)))), 255) 76 | # vor_map = map_generator.whole_new_updated(size=array_size, ppr=2, c1=-1, c2=1, c3=0) 77 | 78 | # combined_map = PertTools.combine_arrays(vor_map, mid_map, 0.33, 0.66) 79 | 80 | # pert_map = PertTools.scale_array(midpoint_generator.normalize(midpoint_generator.NewMidDis(int(math.log(map_width, 2)))), 255) 81 | # vor_map = map_generator.radial_drop(PertTools.pertubate(combined_map, pert_map), 1.5, 0.0) 82 | # vor_map = map_generator.radial_drop(mid_map, 1.5, 0.0) 83 | 84 | 85 | vor_map = map_generator.radial_drop(map_generator.negative(map_generator.reallyCoolFull(array_size, num_p=23)), max_scalar=1.5, min_scalar=0.0) 86 | 87 | 88 | # All grass map for testing 89 | # vor_map = [[150 for x in range(128)] for y in range(128) ] 90 | 91 | # Method without radial drop 92 | # vor_map = map_generator.negative(map_generator.reallyCoolFull(array_size, num_p=23)) 93 | 94 | self.minimap_img = pygame.Surface((map_width, map_height)) 95 | self.tile_array = [[0 for tile_x in range(map_width)] for tile_y in range(map_height)] 96 | self.world_surface = pygame.Surface(self.world_size, pygame.HWSURFACE) 97 | 98 | do_hard_shadow = True 99 | shadow_height = 255 100 | shadow_drop = 3 101 | for tile_x in range(map_width): 102 | 103 | for tile_y in range(map_height): 104 | 105 | color = vor_map[tile_x][tile_y] 106 | 107 | if do_hard_shadow: 108 | shaded = False 109 | if color < shadow_height and not shadow_height < 110: 110 | shaded = True 111 | shadow_height -= shadow_drop 112 | 113 | elif color >= 110 and color > shadow_height: 114 | shadow_height = color 115 | shadow_height -= shadow_drop 116 | 117 | else: 118 | shadow_height -= shadow_drop 119 | 120 | if color < 110: 121 | # Water tile 122 | new_tile = Tile.WaterTile(self, "AndrewWater") 123 | 124 | elif 120 > color >= 110: 125 | # Sand / Beach tile 126 | new_tile = Tile.BeachTile(self, "Sand") 127 | 128 | # TODO: Implement a humidity / temperature system 129 | elif 160 > color >= 120: 130 | # Grass 131 | new_tile = Tile.GrassTile(self, "MinecraftGrass") 132 | 133 | elif 170 > color >= 160: 134 | # Tree 135 | new_tile = Tile.TreePlantedTile(self, "GrassWithCenterTree") 136 | 137 | elif 190 > color >= 170: 138 | # Grass (again) 139 | new_tile = Tile.GrassTile(self, "MinecraftGrass") 140 | 141 | elif 220 > color >= 190: 142 | # Rock 143 | new_tile = Tile.SmoothStoneTile(self, "AndrewSmoothStone") 144 | 145 | else: 146 | # Snow 147 | new_tile = Tile.SnowTile(self, "MinecraftSnow") 148 | 149 | new_tile.location = vector2.Vector2(tile_x * self.tile_size, tile_y * self.tile_size) 150 | 151 | new_tile.rect.topleft = new_tile.location 152 | new_tile.color = color 153 | 154 | alph = 220 - color 155 | if 220 > color >= 190: 156 | alph = 330 - color 157 | new_tile.darkness = alph 158 | 159 | subtle_shadow = pygame.Surface((self.tile_size, self.tile_size)) 160 | subtle_shadow.set_alpha(alph) 161 | 162 | if do_hard_shadow: 163 | hard_shadow = pygame.Surface((self.tile_size, self.tile_size)) 164 | hard_shadow.set_alpha(128) 165 | if shaded: 166 | new_tile.img.blit(hard_shadow, (0, 0)) 167 | 168 | self.world_surface.blit(new_tile.img, new_tile.location) 169 | self.world_surface.blit(subtle_shadow, new_tile.location) 170 | 171 | self.minimap_img.blit( 172 | new_tile.img.subsurface( 173 | (0, 0, 1, 1)), (tile_x, tile_y)) 174 | 175 | self.minimap_img.blit( 176 | subtle_shadow.subsurface( 177 | (0, 0, 1, 1)), (tile_x, tile_y)) 178 | 179 | self.tile_array[tile_y][tile_x] = new_tile 180 | 181 | self.populate() 182 | 183 | def populate(self): 184 | """Populates the world with entities. 185 | 186 | Currently just does a hard-coded a specific number of 187 | lumberjacks and farmers in the same position. 188 | 189 | Args: 190 | None 191 | 192 | Returns: 193 | None""" 194 | 195 | start = {"Lumberjack": {"count": 2, 196 | "state": "Searching", 197 | "class": Lumberjack.Lumberjack}, 198 | 199 | "Angler": {"count": 1, 200 | "state": "Searching", 201 | "class": Angler.Angler}, 202 | 203 | "Arborist": {"count": 1, 204 | "state": "Planting", 205 | "class": Arborist.Arborist}, 206 | 207 | "Farmer": {"count": 0, 208 | "state": "Tilling", 209 | "class": Farmer.Farmer}, 210 | 211 | "Explorer": {"count": 1, 212 | "state": "Exploring", 213 | "class": Explorer.Explorer} 214 | } 215 | 216 | for key in start.keys(): 217 | for count in range(start[key]["count"]): 218 | new_ent = start[key]["class"](self, key) 219 | new_ent.location = vector2.Vector2(self.w / 2, self.h / 2) 220 | new_ent.brain.set_state(start[key]["state"]) 221 | self.add_entity(new_ent) 222 | 223 | def add_entity(self, entity): 224 | """Maps the input entity to the entity hash table (dictionary) 225 | using the entity_id variable, then incriments entity_id. 226 | 227 | Args: 228 | entity: A GameEntity that will be added to the world 229 | 230 | Returns: 231 | None 232 | """ 233 | 234 | self.entities[self.entity_id] = entity 235 | entity.id = self.entity_id 236 | self.entity_id += 1 237 | 238 | def add_building(self, building): 239 | self.buildings[self.building_id] = building 240 | building.id = self.building_id 241 | self.building_id += 1 242 | 243 | for tile_x in range(building.image.get_width()): 244 | for tile_y in range(building.image.get_height()): 245 | self.tile_array[building.location.y + tile_y][building.location.x + tile_x] = Tile.BuildingTile(self, "MinecraftGrass") 246 | self.world_surface.blit(building.image, building.location * self.tile_size) 247 | 248 | def process(self, delta): 249 | """Runs through each entity and runs their process function. 250 | 251 | Args: 252 | delta: Time passed since the last frame (in seconds) 253 | 254 | Returns: 255 | None 256 | """ 257 | 258 | for entity in self.entities.values(): 259 | entity.process(delta) 260 | 261 | def render(self, surface): 262 | """Blits the world_surface and all entities onto surface. 263 | 264 | Args: 265 | surface: The surface on which to blit everything 266 | 267 | Returns: 268 | None 269 | """ 270 | 271 | surface.blit(self.world_surface, self.world_position) 272 | 273 | for entity in self.entities.values(): 274 | entity.render(surface) 275 | if entity.active_info: 276 | self.render_info_bar(surface,entity) 277 | 278 | def render_all(self, surface): 279 | """Calls the clipper's render function, which also calls 280 | this class's render function. Used so the main file doesn't 281 | have to call the clipper. 282 | 283 | Args: 284 | surface: The Pygame.Surface on which to blit everything. 285 | 286 | delta: The time passed (in seconds) since the last frame. 287 | 288 | mouse_pos: tuple of length 2 containing the position of the mouse. 289 | 290 | Returns: 291 | None 292 | """ 293 | self.clipper.render(surface) 294 | 295 | def check_minimap_update(self, mouse_pos): 296 | """This code moves the view to where the user is clicking in 297 | the minimap. Don't ask me how it works, I have no idea. 298 | 299 | Args: 300 | mouse_pos: Vector2 instance that contains the position of the mouse 301 | 302 | Returns: 303 | None 304 | """ 305 | 306 | if (mouse_pos.x > self.clipper.minimap_rect.x and 307 | mouse_pos.y > self.clipper.minimap_rect.y): 308 | 309 | x_temp_1 = -self.clipper.a * (mouse_pos.x - self.clipper.minimap_rect.x) 310 | x_temp_2 = self.clipper.rect_view_w * self.clipper.a 311 | self.world_position.x = x_temp_1 + (x_temp_2 / 2) 312 | 313 | y_temp_1 = -self.clipper.b * (mouse_pos.y - self.clipper.minimap_rect.y) 314 | y_temp_2 = self.clipper.rect_view_h * self.clipper.b 315 | self.world_position.y = y_temp_1 + (y_temp_2 / 2) 316 | 317 | # TODO(wazzup771@gmail.com | Nick Wayne): This function doesn't belong in this class, perhaps the entity superclass. 318 | def render_info_bar(self, surface, entity): 319 | lst = [self.f_high, self.f_low, self.w_high, self.w_low, self.e_high, self.e_low] 320 | lst2 = [entity.food, entity.water, entity.energy] 321 | surface.blit(self.info_bar, (entity.world_location.x + 10, entity.world_location.y - 20)) 322 | for i in range(3): 323 | t = lst2[i] / 100. 324 | r = self.lerp(lst[2 * i][0], lst[2 * i + 1][0], t) 325 | g = self.lerp(lst[2 * i][1], lst[2 * i + 1][1], t) 326 | b = self.lerp(lst[2 * i][2], lst[2 * i + 1][2], t) 327 | pygame.draw.rect(surface, (r, g, b), 328 | pygame.Rect((entity.world_location.x + 20, entity.world_location.y - 14 + (i * 7)), 329 | (int(40 * t), 4))) 330 | 331 | def lerp(self, v1, v2, t): 332 | return (1 - t) * v2 + t * v1 333 | -------------------------------------------------------------------------------- /WorldGOAP.py: -------------------------------------------------------------------------------- 1 | from aitools import GoalMachine 2 | 3 | """This file will be the customized version of the goal machine for this world""" 4 | 5 | class WorldGOAP(GameMachine.GameMachine): 6 | 7 | def __init__(self, world): 8 | GameMachine.GameMachine.__init__(self) 9 | self.world = world 10 | 11 | self.expand_goal = GoalMachine.Goal("expand", 1) 12 | self.wood_goal = GoalMachine.Goal("wood", .5) 13 | self.food_goal = GoalMachine.Goal("food", .5) 14 | self.shelter_goal = GoalMachine.Goal("shelter", .75) 15 | 16 | self.add_goal(self.expand_goal) 17 | self.add_goal(self.wood_goal) 18 | self.add_goal(self.food_goal) 19 | self.add_goal(self.shelter_goal) 20 | 21 | self.spawn_lumberjack_action = GoalMachine.Action("spawn lumberjack", {"wood":-1}) 22 | self.spawn_farmer_action = GoalMachine.Action("spawn farmer", {"wood":-1}) 23 | self.build_house_action = GoalMachine.Action("build house", {"shelter":-1}) 24 | self.build_dock_action = GoalMachine.Action("build dock", {"food":-1}) 25 | self.spawn_fishing_ship_action = GoalMachine.Action("spawn fishing ship", {"food"-1}) 26 | 27 | class SpawnLumberjack(GoalMachine.Action): 28 | 29 | def __init__(self, world): 30 | GoalMachine.Action.__init__("spawn lumberjack", {"wood":-1}) 31 | self.world = world 32 | 33 | def execute(self): 34 | self.world.find_building("Town Center") 35 | -------------------------------------------------------------------------------- /aitools/GoalMachine.py: -------------------------------------------------------------------------------- 1 | class GoalMachine(object): 2 | """Another method for AI, this way you can set general goals for the AI 3 | to accomplish and specific actions it can carry out, and the AI will 4 | determine which actions would make the most sense.""" 5 | 6 | def __init__(self): 7 | self.discontentment = 0 8 | self.max_goal_discontentment = 10 9 | self.goals = {} 10 | self.actions = [] 11 | 12 | def add_goal(self, goal): 13 | self.goals[goal.name] = goal 14 | 15 | def add_action(self, action): 16 | self.actions.append(action) 17 | 18 | def do_action(self, action): 19 | if action is not None: 20 | for effect in action.effects: 21 | self.goals[effect].necessity += action.effects[effect] 22 | 23 | for goal in self.goals: 24 | self.goals[goal].update(action.time) 25 | else: 26 | print "No action selected!" 27 | 28 | def do_reverse_action(self, action): 29 | for effect in action.effects: 30 | self.goals[effect].necessity -= action.effects[effect] 31 | 32 | for goal in self.goals: 33 | self.goals[goal].reverse_update(action.time) 34 | 35 | def calculate_discontentment(self): 36 | discontentment = 0 37 | for goal in self.goals: 38 | discontentment += (self.goals[goal].necessity * self.goals[goal].necessity) 39 | 40 | return discontentment 41 | 42 | def determine_best_action(self): 43 | """Goes through all the possible actions, and determines which would be the most effective""" 44 | 45 | lowest_discontentment = (len(self.goals) * self.max_goal_discontentment) ** 2 46 | best_action = None 47 | current_discontentment = self.calculate_discontentment() 48 | 49 | for possible_action in self.actions: 50 | 51 | self.do_action(possible_action) 52 | 53 | new_possible_discontentment = self.calculate_discontentment() 54 | 55 | if new_possible_discontentment < lowest_discontentment:# and new_possible_discontentment < current_discontentment: 56 | lowest_discontentment = new_possible_discontentment 57 | best_action = possible_action 58 | 59 | self.do_reverse_action(possible_action) 60 | 61 | """ 62 | if best_action is not None: 63 | self.do_action(best_action) 64 | """ 65 | return best_action 66 | 67 | class Goal(object): 68 | """One thing the AI is trying to accomplish.""" 69 | 70 | def __init__(self, name, time_delta=0): 71 | """necessity is how bad the goal should be accomplished, time_delta 72 | is how much it should change over time""" 73 | self.name = name 74 | self.necessity = 0 75 | self.time_delta = time_delta 76 | 77 | def set_necessity(self, value): 78 | self.necessity = value 79 | 80 | def update(self, time_passed): 81 | self.necessity += self.time_delta * time_passed 82 | 83 | def reverse_update(self, time_passed): 84 | self.necessity -= self.time_delta * time_passed 85 | 86 | class Action(object): 87 | """One thing the AI can do to work towards it's goals.""" 88 | 89 | def __init__(self, name, effects, time=0): 90 | """'effects' will be a dictionary of pairs of goal strings with 91 | values of how they will affect them. For example: 92 | {"eat": -2} will decrease the value of the "eat" goal by 2. Time 93 | is how long the action will take (all relative)""" 94 | 95 | self.name = name 96 | self.effects = effects 97 | self.time = time 98 | 99 | def set_time(self, value): 100 | self.time = time 101 | 102 | def execute(self): 103 | """Overwritable""" 104 | pass 105 | 106 | if __name__ == "__main__": 107 | gm = GoalMachine() 108 | 109 | goal1 = Goal("eat", .5) 110 | goal2 = Goal("bathroom", .5) 111 | 112 | goal1.set_necessity(2) 113 | goal2.set_necessity(2) 114 | 115 | action1 = Action("snack", {"eat":-1}, 0.25) 116 | action2 = Action("use_bathroom", {"eat":+2, "bathroom":-2}, 1) 117 | action3 = Action("do nothing", {}, .25) 118 | 119 | gm.add_goal(goal1) 120 | gm.add_goal(goal2) 121 | 122 | gm.add_action(action1) 123 | gm.add_action(action2) 124 | gm.add_action(action3) 125 | 126 | iterations = 10 127 | print "ITERATIONS: ", iterations 128 | 129 | for i in xrange(iterations): 130 | print "\nCURRENT ITERATION:", i+1 131 | 132 | for g in gm.goals: 133 | print gm.goals[g].name, gm.goals[g].necessity 134 | 135 | print "\nCurrent Discontentment:", gm.calculate_discontentment() 136 | best_action1 = gm.determine_best_action() 137 | print "Best Action would be:", best_action1.name 138 | 139 | print "Applying Best Action:" 140 | gm.do_action(best_action1) 141 | 142 | print "New discontentment:", gm.calculate_discontentment(), "\n" 143 | 144 | for g in gm.goals: 145 | print gm.goals[g].name, gm.goals[g].necessity 146 | -------------------------------------------------------------------------------- /aitools/StateMachine.py: -------------------------------------------------------------------------------- 1 | class State(object): 2 | def __init__(self, name): 3 | self.name = name 4 | 5 | def do_actions(self): 6 | pass 7 | 8 | def check_conditions(self): 9 | pass 10 | 11 | def entry_actions(self): 12 | pass 13 | 14 | def exit_actions(self): 15 | pass 16 | 17 | 18 | class StateMachine(object): 19 | def __init__(self): 20 | 21 | self.states = {} 22 | self.active_state = None 23 | 24 | def add_state(self, state): 25 | 26 | self.states[state.name] = state 27 | 28 | def think(self): 29 | 30 | if self.active_state is None: 31 | return 32 | 33 | self.active_state.do_actions() 34 | 35 | new_state_name = self.active_state.check_conditions() 36 | if new_state_name is not None: 37 | self.set_state(new_state_name) 38 | 39 | def set_state(self, new_state_name): 40 | 41 | if self.active_state is not None: 42 | self.active_state.exit_actions() 43 | 44 | self.active_state = self.states[new_state_name] 45 | self.active_state.entry_actions() 46 | -------------------------------------------------------------------------------- /aitools/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ['GoalMachine', 'StateMachine'] 2 | -------------------------------------------------------------------------------- /gametools/ImageFuncs.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | """ 4 | This is a class I wrote to handle cell-based image storage. Rather than store each image 5 | individually you store each image in one large image split up into self.cells, then use subsurfacing 6 | to get each individual image out. w and h are the individual cell width and height, as each image 7 | may take up more than one cell. 8 | """ 9 | 10 | 11 | class ImageFuncs(): 12 | 13 | 14 | def __init__(self, w_cell, h_cell, img): 15 | """ 16 | :param w_cell: width of one cell 17 | :param h_cell: height of one cell 18 | :param img: the image to be divided into cells 19 | :return: nothing 20 | """ 21 | self.w_cell = w_cell 22 | self.h_cell = h_cell 23 | self.img = img 24 | self.get_list(self.img) 25 | 26 | def get_list(self, pic): 27 | """ 28 | :param pic: the picture 29 | :return: None 30 | """ 31 | self.w_img, self.h_img = pic.get_size() 32 | cells = [[0 for i in range(self.w_img // self.w_cell)] for j in range(self.h_img // self.h_cell)] 33 | for i in range(self.w_img // self.w_cell): 34 | for a in range(self.h_img // self.h_cell): 35 | cells[i][a] = pic.subsurface((i*self.w_cell, a*self.h_cell, self.w_cell, self.h_cell)) 36 | self.cells = cells 37 | 38 | def get_cell(self, row, column): 39 | """ 40 | :param row: num of rows in cell 41 | :param column: num of columns in in the pic 42 | :return: The list of images 43 | """ 44 | return self.cells[row][column] 45 | 46 | def get_image(self, x, y): 47 | """ 48 | :param x: x location 49 | :param y: y location 50 | :return: 51 | """ 52 | quick_image = pygame.Surface((self.w_cell, self.h_cell)) 53 | quick_image.blit(self.get_cell(x, y), (0, 0)) 54 | return quick_image 55 | 56 | def get_irregular_image(self, num_w, num_h, x, y): 57 | """ 58 | :param num_w: number width 59 | :param num_h: number height 60 | :param x: x location 61 | :param y: y location 62 | :return: None 63 | """ 64 | quick_image = pygame.Surface((self.w_cell*num_w, self.h_cell*num_h)) 65 | for i in range(num_h): 66 | for g in range(num_w): 67 | quick_image.blit(self.get_cell(x+i, y+g), (i*self.w_cell, g*self.h_cell)) 68 | return quick_image 69 | 70 | def get_images(self, num_images, x, y): 71 | """ 72 | :param num_images: number of images 73 | :param x: x location 74 | :param y: y location 75 | :return: List of images at x,y that is number of images long 76 | """ 77 | lst = [] 78 | for i in range(num_images): 79 | lst.append(self.get_image(x,y)) 80 | x+=1 81 | return lst 82 | -------------------------------------------------------------------------------- /gametools/MidpointDisplacement.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | class MidpointDisplacement(object): 4 | 5 | def NewMidDis(self, N): 6 | WIDTH = HEIGHT = (2 ** N) 7 | to_return = [[0 for x in xrange(WIDTH + 1)] for y in xrange(HEIGHT + 1)] 8 | 9 | to_return[0][0] = random.random() 10 | to_return[WIDTH][0] = random.random() 11 | to_return[WIDTH][HEIGHT] = random.random() 12 | to_return[0][HEIGHT] = random.random() 13 | 14 | for r in xrange(N): 15 | for y in xrange(2 ** r): 16 | for x in xrange(2 ** r): 17 | self.diamond(to_return, r, x, y, N) 18 | 19 | # print r, "iterations done" 20 | # print "size was", ((2 ** N) / (2 ** r)) 21 | # print "there were", 2 ** r, "iterations in each dimension" 22 | # print "" 23 | 24 | return to_return 25 | 26 | def rand_h(self, r): 27 | return (2 * (random.random() - 0.5)) / (2 ** (r + 1)) 28 | 29 | def normalize(self, array): 30 | r_array = array 31 | 32 | min_val = r_array[0][0] 33 | max_val = r_array[0][0] 34 | 35 | for y in xrange(len(r_array)): 36 | for x in xrange(len(r_array[0])): 37 | min_val = min(r_array[x][y], min_val) 38 | max_val = max(r_array[x][y], max_val) 39 | 40 | for y in xrange(len(r_array)): 41 | for x in xrange(len(r_array[0])): 42 | r_array[x][y] -= min_val 43 | r_array[x][y] /= (max_val - min_val) 44 | 45 | return r_array 46 | 47 | def diamond(self, array, recursion_depth, iteration_x, iteration_y, N): 48 | size = ((2 ** N) / (2 ** recursion_depth)) 49 | tl = array[size * iteration_x][size * iteration_y] 50 | tr = array[size * iteration_x + size][size * iteration_y] 51 | br = array[size * iteration_x + size][size * iteration_y + size] 52 | bl = array[size * iteration_x][size * iteration_y + size] 53 | 54 | array[size * iteration_x + size / 2][size * iteration_y + size / 2] = ((tl + tr + br + bl) / 4) + self.rand_h(recursion_depth + 1) 55 | 56 | # Square step 57 | 58 | mid = array[size * iteration_x + size / 2][size * iteration_y + size / 2] 59 | 60 | # top mid 61 | array[size * iteration_x + size / 2][size * iteration_y] = (tl + tr + mid) / 3 + self.rand_h(recursion_depth) 62 | 63 | # right mid 64 | array[size * iteration_x + size][size * iteration_y + size / 2] = (tr + br + mid) / 3 + self.rand_h(recursion_depth) 65 | 66 | # bottom mid 67 | array[size * iteration_x + size / 2][size * iteration_y + size] = (bl + br + mid) / 3 + self.rand_h(recursion_depth) 68 | 69 | # left mid 70 | array[size * iteration_x][size * iteration_y + size / 2] = (tl + bl + mid) / 3 + self.rand_h(recursion_depth) 71 | 72 | def square(self, array, recursion_depth, iteration, N): 73 | pass 74 | 75 | -------------------------------------------------------------------------------- /gametools/PertTools.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Nick Jarvis' 2 | 3 | import math 4 | 5 | def combine_arrays(arr1, arr2, weight1, weight2): 6 | to_return = [[0 for i in xrange(len(arr1))] for j in xrange(len(arr1[0]))] 7 | for y in xrange(len(arr1)): 8 | for x in xrange(len(arr1[0])): 9 | to_return[x][y] = arr1[x][y] * weight1 + arr2[x][y] * weight2 10 | 11 | return to_return 12 | 13 | def clamp(val, low=0, high=255): 14 | return max(min(high, val), low) 15 | 16 | def scale_array(array, scalar): 17 | to_return = array 18 | for y in xrange(len(array)): 19 | for x in xrange(len(array[0])): 20 | to_return[x][y] = array[x][y] * scalar 21 | 22 | return to_return 23 | 24 | def pertubate(base_array, pert_array): 25 | to_return = [[0 for y in xrange(len(base_array))] for x in xrange(len(base_array[0]))] 26 | size = len(base_array) - 1 27 | 28 | magnitude = math.log(size + 1, 2) * ((size + 1) / 256) 29 | 30 | for y in xrange(len(base_array)): 31 | for x in xrange(len(base_array[0])): 32 | offset = int(((pert_array[x][y] - 128) / 128.0) * magnitude) 33 | to_return[x][y] = clamp(base_array[clamp(x + offset, high=size)][clamp(y + offset, high=size)], 0, 255) 34 | 35 | return to_return 36 | 37 | -------------------------------------------------------------------------------- /gametools/VoronoiMapGen.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import math 3 | import pygame 4 | from random import randint 5 | 6 | @functools.total_ordering 7 | class point(object): 8 | 9 | def __init__(self, pos, color=False): 10 | """Basic point, this will be used for the "feature points" 11 | these will hold their position, as well as a separate x and y 12 | variable for easy use. Also a distance variable will be assigned 13 | for when calculating the voronoi diagram""" 14 | 15 | self.pos = pos 16 | self.x = pos[0] 17 | self.y = pos[1] 18 | self.distance = 0 19 | self.color = None 20 | if color: self.color = randint(0, 255) 21 | self.current_point = None 22 | 23 | def get_distance(self, p2): 24 | """Basic distance formula. Doesn't square root everything 25 | in order to speed up the process (AKA Manhattan Distance) """ 26 | 27 | try: 28 | distance = float((p2.x - self.x) ** 2) + ((p2.y - self.y) ** 2) 29 | except ZeroDivisionError: 30 | distance = 0 31 | except AttributeError: 32 | distance = 0 33 | self.distance = distance 34 | return distance 35 | 36 | def add_color(self): 37 | if randint(0, 1): 38 | self.color = randint(1, 10) * 10 39 | else: 40 | self.color = 0 41 | 42 | def __eq__(self, other): 43 | return self.x == other.x and self.y == other.y 44 | 45 | def __lt__(self, other): 46 | return self.get_distance(self.current_point) < other.get_distance(self.current_point) 47 | 48 | 49 | class mapGen: 50 | 51 | def lerp(self, c1, c2, a): 52 | return c1 + (c2 - c1) * a 53 | 54 | def whole_new(self, num_R, size=(256, 256), c1=0, c2=0, c3=0): 55 | """DEPRECATED 56 | Creates 1 image of the voronoi diagram. I only listed the first 3 57 | coefficients because that's all I will really need, but feel free 58 | to add more""" 59 | 60 | w, h = size #Very easy to use w and h instead of size[0] and size[1] 61 | 62 | toReturn = [[0 for _ in range(size[0])] for _ in range(size[1])] 63 | 64 | point_list = [point((randint(0, w), randint(0, h))) for i in range(num_R)] 65 | #Creates the random "interest" points, 66 | 67 | for y in range(h): #Do row-by-row instead of 68 | for x in range(w): #collumn-by-collumn 69 | currentPoint = point((x, y)) 70 | for p in point_list: 71 | p.current_point = currentPoint 72 | 73 | point_list.sort() # sorted(point_list, key=lambda point: point.get_distance(currentPoint)) #sort the points in a new list by their distance from the current point 74 | #(new_pointlist) 75 | 76 | currentPoint.brightness = int(c1*point_list[0].distance+c2*point_list[1].distance+c3*point_list[2].distance)/(num_R*(size[0]/((512.0/size[0])*256))) 77 | #this uses the coefficients and the new list to find the brightness of the wanted pixel 78 | #the math at the end is something I came to after about a half hour of fiddling around 79 | #with values. This will keep the value at a constant and good level, and not flatten anything. 80 | 81 | #maxB = max(maxB, currentPoint.brightness) 82 | #minB = min(minB, currentPoint.brightness) 83 | 84 | clr = abs(currentPoint.brightness) #a lot of the times the values are negative! 85 | clr = min(255, clr) #Make sure we don't for some reason overflow 86 | toReturn[x][y] = clr 87 | 88 | return toReturn 89 | 90 | def whole_new_updated(self, size=(256, 256), rpd=4, ppr=3, c1=0, c2=0, c3=0): 91 | """Creates and returns an array of given size containing values calculated by a voronoi diagram. 92 | 93 | The updated version is more controlled, with regions per dimension (rpd) and points per region (ppr). The array 94 | is split up into rpd * rpd regions, while each region contains ppr interest points. These points are used along 95 | with coefficients c1, c2, and c3 to customize the array. 96 | 97 | Arguments: 98 | size: 99 | The size of the return array. This should probably just be an 100 | integer to keep the array square in the future. 101 | rpd: 102 | This is the amount of regions on each side of the diagram. 103 | A value of 4 would result in 16 regions, 4 on each side. 104 | ppr: 105 | The amount of interest points in a region. Randomly distributed 106 | c1, c2, c3: 107 | Coeffiecients that determine how the final outcome will be. 108 | A c1 of 1 and the rest 0's will result in 'bubbles', while 109 | a c1 of 1 and a c2 of -1 will result in straight lines that 110 | divide the diagram into regions 111 | 112 | Returns a 2-Dimensional array with size equal to the argument size.""" 113 | 114 | w, h = size 115 | to_return = [[0 for i in range(w)] for j in range(h)] 116 | num_regions = rpd * rpd 117 | region_size = size[0] / rpd 118 | num_points = num_regions * ppr 119 | 120 | interest_points = [] 121 | 122 | for region_y in range(rpd): 123 | for region_x in range(rpd): 124 | 125 | for p in range(ppr): 126 | rx = randint(region_x * region_size, (region_x + 1) * region_size) 127 | ry = randint(region_y * region_size, (region_y + 1) * region_size) 128 | interest_points.append(point((rx, ry))) 129 | 130 | max_val = 0 131 | min_val = 0 132 | 133 | for y in range(h): 134 | for x in range(w): 135 | current_point = point((x, y)) 136 | for p in interest_points: 137 | p.current_point = interest_points 138 | 139 | #sort the points in a new list by their distance from the current point 140 | #new_pointlist = sorted(interest_points, key=lambda point: point.get_distance(current_point)) 141 | interest_points.sort() 142 | 143 | current_point.brightness = c1 * interest_points[0].distance + \ 144 | c2 * interest_points[1].distance + \ 145 | c3 * interest_points[2].distance 146 | 147 | if y == x == 0: 148 | max_val = current_point.brightness 149 | min_val = current_point.brightness 150 | 151 | elif current_point.brightness > max_val: 152 | max_val = current_point.brightness 153 | 154 | elif current_point.brightness < min_val: 155 | min_val = current_point.brightness 156 | 157 | to_return[x][y] = current_point.brightness 158 | 159 | max_val -= min_val 160 | # print max_val, min_val 161 | for y in range(h): 162 | for x in range(w): 163 | to_return[x][y] -= min_val 164 | 165 | to_return[x][y] = int((to_return[x][y] / max_val) * 255) 166 | 167 | return to_return 168 | 169 | def flat(self, num_R, size=(256, 256)): 170 | """ 171 | Creates 1 image of the voronoi diagram. I only listed the first 3 172 | coefficients because that's all I will really need, but feel free 173 | to add more""" 174 | 175 | w, h = size # Very easy to use w and h instead of size[0] and size[1] 176 | 177 | toReturn = [[0 for i in range(size[0])] for j in range(size[1])] 178 | 179 | point_list = [point((randint(0, w), randint(0, h)),True) for i in range(num_R)] #Creates the random "interest" points, 180 | for POINT in point_list: 181 | POINT.addColor() 182 | 183 | for y in range(h): #Do row-by-row instead of 184 | for x in range(w): #collumn-by-collumn 185 | currentPoint = point((x, y)) 186 | for p in point_list: 187 | p.current_point = currentPoint 188 | 189 | point_list.sort() # = sorted(point_list, key=lambda point: point.get_distance(currentPoint)) #sort the points in a new list by their distance from the current point 190 | 191 | currentPoint.brightness = point_list[0].color 192 | clr = abs(currentPoint.brightness) 193 | clr = min(255, clr) 194 | 195 | toReturn[x][y] = clr 196 | 197 | return toReturn 198 | 199 | def lerp_two_images(self, pic1, pic2, a): 200 | w, h = len(pic1), len(pic1[0]) #pic1.get_size() 201 | surface = pygame.Surface((w, h)) 202 | 203 | for y in range(h): 204 | for x in range(w): 205 | clr1 = pic1.get_at((x, y)) 206 | clr2 = pic2.get_at((x, y)) 207 | clrR = (clr1[0]*(1-a)+clr2[0]*a) 208 | clrG = (clr1[1]*(1-a)+clr2[1]*a) 209 | clrB = (clr1[2]*(1-a)+clr2[2]*a) 210 | try: 211 | surface.set_at((x, y), (clrR, clrG, clrB)) 212 | except TypeError as e: 213 | print(clr) 214 | raise e 215 | 216 | return surface 217 | 218 | def combine_images(self, *pics): 219 | #Takes a list of images and combines them (grayscale). 220 | #All picture sizes must be of equal or less length 221 | #but it is reccomended to have the exact same size for each 222 | 223 | num_pics = len(pics) 224 | w, h= len(pics[0]), len(pics[0][0])#Again, this is very nice for keeping things quick 225 | 226 | total_map = [[0 for i in range(h)] for i in range(w)] #Create a 2D array to hold all the values 227 | for PIC in pics: #Loops through each of the given pictures 228 | for y in range(h): #Row-by-Row 229 | for x in range(w): 230 | try: 231 | total_map[x][y] += PIC[x][y] #Adds the current value at the map to the corresponding cell on the array 232 | except IndexError as err: 233 | print(x, y) 234 | print(len(total_map), len(total_map[0])) 235 | raise err 236 | 237 | to_return = [[0 for i in range(h)] for j in range(w)] 238 | for y in range(h): #Loop through again, row-by-row 239 | for x in range(w): 240 | total_map[x][y]/=num_pics #average out each cell 241 | clr = total_map[x][y] #use clr so we don't have to use 'total_map[x][y]' 3 times 242 | to_return[x][y] = clr 243 | 244 | return to_return 245 | 246 | def threshold(self, array, lower=100, upper=128): 247 | #returns a thresholded surface of the image provided 248 | #NOTE: array must have equal size dimensions 249 | 250 | w = h = len(array) 251 | toReturn = [[0 for x in range(w)] for y in range(h)] 252 | for y in range(h): #Row-by-Row 253 | for x in range(w): 254 | if lower <= array[x][y] <= upper: #Checks to see if the value is in the threshold 255 | toReturn[x][y] = 255 #Sets the pixel at that position to white if it is 256 | 257 | return toReturn 258 | 259 | def negative(self, ARRAY): 260 | w = h = len(ARRAY) 261 | toReturn = [[0 for x in range(w)]for y in range(h)] 262 | for y in range(h): 263 | for x in range(w): 264 | toReturn[x][y] = 255-ARRAY[x][y] 265 | 266 | return toReturn 267 | 268 | def radial_drop(self, array, max_scalar=1.0, min_scalar=0.5, fast=True): 269 | height, width = len(array), len(array[0]) 270 | center_y, center_x = height / 2, width / 2 271 | 272 | if fast: 273 | max_dis = center_x ** 2 + center_y ** 2 274 | else: 275 | max_dis = math.sqrt(center_x ** 2 + center_y ** 2) 276 | 277 | to_return = array[:] 278 | for y in range(height): 279 | for x in range(width): 280 | if fast: 281 | t = ((x - center_x) ** 2 + (y - center_y) ** 2) / float(max_dis) 282 | else: 283 | t = math.sqrt((x - center_x) ** 2 + (y - center_y) ** 2) / max_dis 284 | 285 | to_return[x][y] *= self.lerp(max_scalar, min_scalar, t) 286 | 287 | return to_return 288 | 289 | 290 | 291 | 292 | def reallyCoolFull(self, total_size=(256,256), num_p=25): 293 | #Uses 4 (or as many as you make, but I have found this to look cool) 294 | #calls to "whole_new()" and averages them out to create one cool image 295 | #that can be used in map generation! :D 296 | 297 | pic1 = self.whole_new(num_p, total_size, c1=-1) 298 | pic2 = self.whole_new(num_p, total_size, c2=1) 299 | pic3 = self.whole_new(num_p, total_size, c3=1) 300 | pic4 = self.whole_new(num_p, total_size, c1=-1, c2=1) 301 | 302 | return self.combine_images(pic1, pic2, pic3, pic4) 303 | 304 | def full_updated(self, size=(256, 256), rpd=4, ppr=3): 305 | pic1 = self.whole_new_updated(size, rpd, ppr, c1=-1) 306 | pic2 = self.whole_new_updated(size, rpd, ppr, c2=1) 307 | pic3 = self.whole_new_updated(size, rpd, ppr, c3=1) 308 | pic4 = self.whole_new_updated(size, rpd, ppr, c1=-1, c2=1) 309 | 310 | return self.combine_images(pic1, pic2, pic3, pic4) 311 | -------------------------------------------------------------------------------- /gametools/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ['vector2', 'util', 'VoronoiMapGen', 'ImageLoader', 'ImageFuncs','ani'] 2 | -------------------------------------------------------------------------------- /gametools/ani.py: -------------------------------------------------------------------------------- 1 | class Ani(object): 2 | """ 3 | Creates an animation given the cell width, height, and the image and it returns the image needed at the time passed 4 | in seconds 5 | """ 6 | 7 | def __init__(self,num,counter): 8 | self.counter_max = counter 9 | self.counter = counter 10 | self.finished = False 11 | self.ani_num_max = num 12 | self.ani_num = 0 13 | 14 | 15 | def reset(self): 16 | self.counter = self.counter_max 17 | self.ani_num = 0 18 | 19 | 20 | def get_frame(self): 21 | self.counter -= 1 22 | if self.counter <= 0: 23 | self.counter = self.counter_max 24 | self.ani_num += 1 25 | if self.ani_num == self.ani_num_max: 26 | self.reset() 27 | self.finished = True 28 | return self.ani_num 29 | 30 | 31 | -------------------------------------------------------------------------------- /gametools/util.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def format_number(n, accuracy=6): 4 | """Formats a number in a friendly manner 5 | (removes trailing zeros and unneccesary point. 6 | """ 7 | fs = "%." + str(accuracy) + "f" 8 | str_n = fs % float(n) 9 | if '.' in str_n: 10 | str_n = str_n.rstrip('0').rstrip('.') 11 | if str_n == "-0": 12 | str_n = "0" 13 | #str_n = str_n.replace("-0", "0") 14 | return str_n 15 | 16 | 17 | def lerp(a, b, i): 18 | """Linear enterpolate from a to b.""" 19 | return a + (b - a) * i 20 | 21 | 22 | def range2d(range_x, range_y): 23 | """Creates a 2D range. 24 | """ 25 | range_x = list(range_x) 26 | return [(x, y) for y in range_y for x in range_x] 27 | 28 | 29 | def xrange2d(range_x, range_y): 30 | """Iterates over a 2D range. 31 | """ 32 | range_x = list(range_x) 33 | for y in range_y: 34 | for x in range_x: 35 | yield (x, y) 36 | 37 | 38 | def saturate(value, low, high): 39 | return min(max(value, low), high) 40 | 41 | 42 | def is_power_of_2(n): 43 | """Returns True if a value is a power of 2.""" 44 | return math.log(n, 2) % 1.0 == 0.0 45 | 46 | 47 | def next_power_of_2(n): 48 | """Returns the next power of 2 that is >= n""" 49 | return int(2 ** math.ceil(math.log(n, 2))) 50 | 51 | if __name__ == "__main__": 52 | pass 53 | #print list(xrange2d(xrange(3), xrange(3))) 54 | #print range2d(xrange(3), xrange(3)) 55 | #print is_power_of_2(7) 56 | #print is_power_of_2(8) 57 | #print is_power_of_2(9) 58 | #print next_power_of_2(7) 59 | -------------------------------------------------------------------------------- /gametools/vector2.py: -------------------------------------------------------------------------------- 1 | from math import sqrt 2 | from gametools.util import format_number 3 | 4 | class Vector2(object): 5 | 6 | __slots__ = ('_v', ) 7 | _gameobjects_vector = 2 8 | 9 | def __init__(self, x=0., y=0.): 10 | """Initialise a vector 11 | 12 | @type x: number 13 | @param x: The x value (defaults to 0.), or a container of 2 values 14 | @type x: number 15 | @param y: The y value (defaults to 0.) 16 | 17 | """ 18 | if hasattr(x, "__getitem__"): 19 | x, y = x 20 | self._v = [float(x), float(y)] 21 | else: 22 | self._v = [float(x), float(y)] 23 | 24 | def _get_length(self): 25 | x, y = self._v 26 | return sqrt(x * x + y * y) 27 | 28 | def _set_length(self, length): 29 | v = self._v 30 | try: 31 | x, y = v 32 | l = length / sqrt(x * x + y * y) 33 | except ZeroDivisionError: 34 | v[0] = 0.0 35 | v[1] = 0.0 36 | return self 37 | v[0] *= l 38 | v[1] *= l 39 | length = property(_get_length, _set_length, None, "Length of the vector") 40 | 41 | @classmethod 42 | def from_floats(cls, x, y): 43 | vec = cls.__new__(cls, object) 44 | vec._v = [x, y] 45 | return vec 46 | 47 | @classmethod 48 | def from_iter(cls, iterable): 49 | """Creates a Vector2 object from an iterable. 50 | 51 | @param iterable: An iterable of at least 2 numeric values 52 | """ 53 | next = iter(iterable).next 54 | vec = cls.__new__(cls, object) 55 | vec._v = [float(next()), float(next())] 56 | return vec 57 | 58 | @classmethod 59 | def from_points(cls, p1, p2): 60 | """Creates a Vector2 object between two points. 61 | @param p1: First point 62 | @param p2: Second point 63 | """ 64 | v = cls.__new__(cls, object) 65 | x, y = p1 66 | xx, yy = p2 67 | v._v = [float(xx - x), float(yy - y)] 68 | return v 69 | 70 | @classmethod 71 | def _from_float_sequence(cls, sequence): 72 | v = cls.__new__(cls, object) 73 | v._v = list(sequence[:2]) 74 | return v 75 | 76 | def copy(self): 77 | """Returns a copy of this object.""" 78 | vec = self.__new__(self.__class__, object) 79 | vec._v = self._v[:] 80 | return vec 81 | 82 | def get_x(self): 83 | return self._v[0] 84 | 85 | def set_x(self, x): 86 | try: 87 | self._v[0] = 1.0 * x 88 | except: 89 | raise TypeError("Must be a number") 90 | x = property(get_x, set_x, None, "x component.") 91 | 92 | def get_y(self): 93 | return self._v[1] 94 | 95 | def set_y(self, y): 96 | try: 97 | self._v[1] = 1.0 * y 98 | except: 99 | raise TypeError("Must be a number") 100 | y = property(get_y, set_y, None, "y component.") 101 | 102 | #u = property(get_x, set_y, None, "u component (alias for x).") 103 | #v = property(get_y, set_y, None, "v component (alias for y).") 104 | 105 | def __str__(self): 106 | x, y = self._v 107 | return "(%s, %s)" % (format_number(x), format_number(y)) 108 | 109 | def __repr__(self): 110 | x, y = self._v 111 | return "Vector2(%s, %s)" % (x, y) 112 | 113 | def __iter__(self): 114 | return iter(self._v[:]) 115 | 116 | def __len__(self): 117 | return 2 118 | 119 | def __getitem__(self, index): 120 | """Gets a component as though the vector were a list.""" 121 | try: 122 | return self._v[index] 123 | except IndexError: 124 | raise IndexError( 125 | "There are 2 values in this object, index should be 0 or 1") 126 | 127 | def __setitem__(self, index, value): 128 | """Sets a component as though the vector were a list.""" 129 | 130 | try: 131 | self._v[index] = 1.0 * value 132 | except IndexError: 133 | raise IndexError( 134 | "There are 2 values in this object, index should be 0 or 1!") 135 | except TypeError: 136 | raise TypeError("Must be a number") 137 | 138 | def __eq__(self, rhs): 139 | x, y = self._v 140 | xx, yy = rhs 141 | return x == xx and y == yy 142 | 143 | def __ne__(self, rhs): 144 | x, y = self._v 145 | xx, yy, = rhs 146 | return x != xx or y != yy 147 | 148 | def __hash__(self): 149 | 150 | return hash(self._v) 151 | 152 | def __add__(self, rhs): 153 | x, y = self._v 154 | xx, yy = rhs 155 | return Vector2.from_floats(x + xx, y + yy) 156 | 157 | def __iadd__(self, rhs): 158 | xx, yy = rhs 159 | v = self._v 160 | v[0] += xx 161 | v[1] += yy 162 | return self 163 | 164 | def __radd__(self, lhs): 165 | x, y = self._v 166 | xx, yy = lhs 167 | return self.from_floats(x + xx, y + yy) 168 | 169 | def __sub__(self, rhs): 170 | x, y = self._v 171 | xx, yy = rhs 172 | return Vector2.from_floats(x - xx, y - yy) 173 | 174 | def __rsub__(self, lhs): 175 | x, y = self._v 176 | xx, yy = lhs 177 | return self.from_floats(xx - x, yy - y) 178 | 179 | def _isub__(self, rhs): 180 | xx, yy = rhs 181 | v = self._v 182 | v[0] -= xx 183 | v[1] -= yy 184 | return self 185 | 186 | def __mul__(self, rhs): 187 | """Return the result of multiplying this vector with a 188 | scalar or a vector-list object.""" 189 | x, y = self._v 190 | if hasattr(rhs, "__getitem__"): 191 | xx, yy = rhs 192 | return Vector2.from_floats(x * xx, y * yy) 193 | else: 194 | return Vector2.from_floats(x * rhs, y * rhs) 195 | 196 | def __imul__(self, rhs): 197 | """Multiplys this vector with a scalar or a vector-list object.""" 198 | if hasattr(rhs, "__getitem__"): 199 | xx, yy = rhs 200 | v = self._v 201 | v[0] *= xx 202 | v[1] *= yy 203 | else: 204 | v = self._v 205 | v[0] *= rhs 206 | v[1] *= rhs 207 | return self 208 | 209 | def __rmul__(self, lhs): 210 | 211 | x, y = self._v 212 | if hasattr(lhs, "__getitem__"): 213 | xx, yy = lhs 214 | else: 215 | xx = lhs 216 | yy = lhs 217 | return self.from_floats(x * xx, y * yy) 218 | 219 | def __div__(self, rhs): 220 | """Return the result of dividing this vector by a scalar 221 | or a vector-list object. 222 | """ 223 | x, y = self._v 224 | if hasattr(rhs, "__getitem__"): 225 | xx, yy, = rhs 226 | return Vector2.from_floats(x / xx, y / yy) 227 | else: 228 | return Vector2.from_floats(x / rhs, y / rhs) 229 | 230 | def __idiv__(self, rhs): 231 | """Divides this vector with a scalar or a vector-list object.""" 232 | if hasattr(rhs, "__getitem__"): 233 | xx, yy = rhs 234 | v = self._v 235 | v[0] /= xx 236 | v[1] /= yy 237 | else: 238 | v = self._v 239 | v[0] /= rhs 240 | v[1] /= rhs 241 | return self 242 | 243 | def __rdiv__(self, lhs): 244 | 245 | x, y = self._v 246 | if hasattr(lhs, "__getitem__"): 247 | xx, yy = lhs 248 | else: 249 | xx = lhs 250 | yy = lhs 251 | return self.from_floats(xx / x, yy / x) 252 | 253 | def __neg__(self): 254 | """Return the negation of this vector.""" 255 | x, y = self._v 256 | return Vector2.from_floats(-x, -y) 257 | 258 | def __pos__(self): 259 | 260 | return self.copy() 261 | 262 | def __nonzero__(self): 263 | 264 | x, y = self._v 265 | return bool(x or y) 266 | 267 | def __call__(self, keys): 268 | 269 | """Used to swizzle a vector. 270 | 271 | @type keys: string 272 | @param keys: A string containing a list of component names 273 | >>> vec = Vector(1, 2) 274 | >>> vec('yx') 275 | (1, 2) 276 | 277 | """ 278 | 279 | ord_x = ord('x') 280 | v = self._v 281 | return tuple(v[ord(c) - ord_x] for c in keys) 282 | 283 | def as_tuple(self): 284 | """Converts this vector to a tuple. 285 | 286 | @rtype: Tuple 287 | @return: Tuple containing the vector components 288 | """ 289 | return tuple(self._v) 290 | 291 | def get_length(self): 292 | """Returns the length of this vector.""" 293 | x, y = self._v 294 | return sqrt(x * x + y * y) 295 | get_magnitude = get_length 296 | 297 | def normalise(self): 298 | """Normalises this vector.""" 299 | v = self._v 300 | x, y = v 301 | l = sqrt(x * x + y * y) 302 | try: 303 | v[0] /= l 304 | v[1] /= l 305 | except ZeroDivisionError: 306 | v[0] = 0. 307 | v[1] = 0. 308 | return self 309 | normalize = normalise 310 | 311 | def get_normalised(self): 312 | x, y = self._v 313 | l = sqrt(x * x + y * y) 314 | return Vector2.from_floats(x / l, y / l) 315 | get_normalized = get_normalised 316 | 317 | def get_distance_to(self, p): 318 | """Returns the distance to a point. 319 | 320 | @param: A Vector2 or list-like object with at least 2 values. 321 | @return: distance 322 | """ 323 | x, y = self._v 324 | xx, yy = p 325 | dx = xx - x 326 | dy = yy - y 327 | return sqrt(dx * dx + dy * dy) 328 | 329 | if __name__ == "__main__": 330 | 331 | v1 = Vector2(1, 2) 332 | #print v1('yx') 333 | #print Vector2.from_points((5, 5), (10, 10)) 334 | -------------------------------------------------------------------------------- /gametools3/MidpointDisplacement3.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | 3 | __author__ = 'Nick Jarvis' 4 | 5 | import numpy as np 6 | import random 7 | 8 | v = np.random.rand(5, 5) 9 | u = np.full((5, 5), 3, dtype=np.dtype('d')) 10 | 11 | print(v * u) 12 | -------------------------------------------------------------------------------- /gametools3/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Nick Jarvis' 2 | -------------------------------------------------------------------------------- /misctools/NewIcon.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | pygame.init() 4 | 5 | screen = pygame.display.set_mode((10, 10)) 6 | 7 | red_color = (200, 50, 50) 8 | yellow_color = (128, 128, 0) 9 | 10 | 11 | class new_icon_maker(object): 12 | def __init__(self): 13 | pass 14 | 15 | def get_icon(self, big, tile, size, name): 16 | new_surface = pygame.Surface(big.get_size()) 17 | x, y = big.get_size()[0]/int(size), big.get_size()[1]/int(size) 18 | for i in range(x): 19 | for a in range(y): 20 | new_surface.blit(tile, (i*size, a*size)) 21 | 22 | new_surface.blit(big, (0, 0)) 23 | pygame.image.save(new_surface, "Images/Buildings/%s_Icon.png"%name) 24 | return new_surface 25 | 26 | def color(self, big, tile, size, name, color): 27 | first_img = self.get_icon(big, tile, size, name) 28 | 29 | test_surface = pygame.Surface((64, 64)) 30 | test_surface.set_alpha(128) 31 | 32 | if color == "RED": 33 | test_surface.fill(red_color) 34 | elif color == "SELECTED": 35 | test_surface.fill(yellow_color) 36 | 37 | final_icon = pygame.Surface((64, 64)) 38 | final_icon.blit(first_img, (0, 0)) 39 | final_icon.blit(test_surface, (0, 0)) 40 | 41 | pygame.image.save(final_icon, "Images/Buildings/%s_%s_Icon.png"%(color, name)) 42 | 43 | 44 | maker = new_icon_maker() 45 | 46 | big_img = pygame.image.load("Images/Buildings/TotalImage.png").convert().subsurface(64, 192, 64, 64) 47 | big_img.set_colorkey((255, 0, 255)) 48 | 49 | tile_img = pygame.image.load("Images/Tiles/MinecraftGrass.png").convert() 50 | icon1 = maker.get_icon(big_img, tile_img, 32, "TownHall") 51 | -------------------------------------------------------------------------------- /misctools/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ['NewIcon'] 2 | --------------------------------------------------------------------------------