Initial Commit
This commit is contained in:
commit
14c182a39c
72
README.md
Normal file
72
README.md
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
# emPYre
|
||||||
|
(should change as soon as the game is more complete)
|
||||||
|
|
||||||
|
## About
|
||||||
|
EmPYre is an (experimental) python 3 implementation of the old Empire game.
|
||||||
|
|
||||||
|
### Why?
|
||||||
|
The current port on Ubuntu is slow AF and also the control-scheme like many tools from that era it didn't era very well. (ignoring features we see in modern open-source RTS-games these days)
|
||||||
|
|
||||||
|
# Requirements
|
||||||
|
* Python 3.4+
|
||||||
|
|
||||||
|
# Developer notes
|
||||||
|
TODO:
|
||||||
|
* Look into how the original version did the battle system ( units vs units vs cities )
|
||||||
|
* Look into ASCII, Colours, blinking and other flashy things
|
||||||
|
* + land
|
||||||
|
* . sea
|
||||||
|
* ^ (mountains?)
|
||||||
|
* Look into nCurses to deal with the interface issues
|
||||||
|
* Different parts of the screen
|
||||||
|
* Pop-up a window if something is required?
|
||||||
|
* Look into how to do this
|
||||||
|
* Separate the logic from the interface?
|
||||||
|
* Multiple opponents?
|
||||||
|
* Multi-player?
|
||||||
|
* Multi-session multi-player?
|
||||||
|
* Modern systems
|
||||||
|
* Waypoints?
|
||||||
|
* Build-queues?
|
||||||
|
* Patrols?
|
||||||
|
|
||||||
|
## Combat
|
||||||
|
|
||||||
|
``` while (att_obj->hits > 0 && def_obj->hits > 0) {
|
||||||
|
if (irand (2) == 0) /* defender hits? */
|
||||||
|
att_obj->hits -= piece_attr[def_obj->type].strength;
|
||||||
|
else def_obj->hits -= piece_attr[att_obj->type].strength;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|Piece|You|Enemy|Moves|Hits|Str|Cost|
|
||||||
|
| --- | ---| ---| ---| ---| ---| ---|
|
||||||
|
|Army|A|a|1|1|1|5(6)|
|
||||||
|
|Fighter|F|f|8|1|1|10(12)|
|
||||||
|
|Patrol Boat|P|p|4|1|1|15(18)|
|
||||||
|
|Destroyer|D|d|2|3|1|20(24)|
|
||||||
|
|Submarine|S|s|2|2|3|20(24)|
|
||||||
|
|Troop Transport|T|t|2|1|1|30(36)|
|
||||||
|
|Aircraft Carrier|C|c|2|8|1|30(36)|
|
||||||
|
|Battleship|B|b|2|10|2|40(48)|
|
||||||
|
|Satellite|Z|z|10|--|--|50(60)|
|
||||||
|
|
||||||
|
Other details: http://www.catb.org/~esr/vms-empire/vms-empire.html
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
typedef struct piece_attr {
|
||||||
|
char sname; /* eg 'C' */
|
||||||
|
char name[20]; /* eg "aircraft carrier" */
|
||||||
|
char nickname[20]; /* eg "carrier" */
|
||||||
|
char article[20]; /* eg "an aircraft carrier" */
|
||||||
|
char plural[20]; /* eg "aircraft carriers" */
|
||||||
|
char terrain[4]; /* terrain piece can pass over eg "." */
|
||||||
|
uchar build_time; /* time needed to build unit */
|
||||||
|
uchar strength; /* attack strength */
|
||||||
|
uchar max_hits; /* number of hits when completely repaired */
|
||||||
|
uchar speed; /* number of squares moved per turn */
|
||||||
|
uchar capacity; /* max objects that can be held */
|
||||||
|
long range; /* range of piece */
|
||||||
|
} piece_attr_t;
|
||||||
|
```
|
21
empyre.py
Normal file
21
empyre.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Import mapgen
|
||||||
|
# Import state-engine
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Main loop
|
||||||
|
# Check if there is a save-file
|
||||||
|
# Load Gamestate
|
||||||
|
# Else
|
||||||
|
# Generate Gamestate
|
||||||
|
# Generate map+assesories
|
||||||
|
# Create a fog of war
|
||||||
|
# Create extra metadata entries: round# movesPlayer movesAI Stats turn(c or p)
|
||||||
|
|
||||||
|
# Look who's turn it is
|
||||||
|
# If its Computer
|
||||||
|
# Magic happens here
|
||||||
|
# else
|
||||||
|
# Player's turn
|
||||||
|
# Iterate through cities
|
||||||
|
# Iterate through units
|
28
experiments/animateLacunarity.py
Normal file
28
experiments/animateLacunarity.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
from PIL import Image, ImageDraw
|
||||||
|
import noise
|
||||||
|
|
||||||
|
slides = []
|
||||||
|
width=500
|
||||||
|
height=500
|
||||||
|
#cycles=5948
|
||||||
|
cycles=595
|
||||||
|
divider=1000
|
||||||
|
divider=100
|
||||||
|
|
||||||
|
for lacu in range(0,cycles):
|
||||||
|
|
||||||
|
print("Lacunarity: "+str(round(lacu/divider,3)) )
|
||||||
|
|
||||||
|
img = Image.new('RGB', (width,height))
|
||||||
|
|
||||||
|
for x in range(1,width):
|
||||||
|
for y in range(1,height):
|
||||||
|
area = noise.pnoise2( x/128, y/128, octaves=50, persistence=0.5, lacunarity=round(lacu/divider,3), repeatx=width, repeaty=height, base=25 )
|
||||||
|
img.putpixel( (int(x),int(y)), round(area*255) )
|
||||||
|
|
||||||
|
d = ImageDraw.Draw(img)
|
||||||
|
d.text( (1,1), "Lacunarity: "+str(round(lacu/divider,3)), fill=(255,0,0))
|
||||||
|
|
||||||
|
slides.append(img)
|
||||||
|
|
||||||
|
slides[0].save("lacunarity.gif", save_all=True, append_images=slides[1:], optimize=True, duration=50, loop=0)
|
68
experiments/camera.py
Normal file
68
experiments/camera.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
# Import 1st party modules
|
||||||
|
import curses
|
||||||
|
|
||||||
|
# Import my own libraries
|
||||||
|
from state import State
|
||||||
|
|
||||||
|
gamestate = State()
|
||||||
|
gamestate.load()
|
||||||
|
|
||||||
|
#print(gamestate.terrain[1][2])
|
||||||
|
|
||||||
|
def draw_map(stdscr):
|
||||||
|
# key press
|
||||||
|
k = 0
|
||||||
|
|
||||||
|
# Map center
|
||||||
|
center = {}
|
||||||
|
center['x'] = round(gamestate.metadata['width']/2)
|
||||||
|
center['y'] = round(gamestate.metadata['height']/2)
|
||||||
|
|
||||||
|
# Clear and refresh the screen for a blank canvas
|
||||||
|
stdscr.clear()
|
||||||
|
stdscr.refresh()
|
||||||
|
|
||||||
|
# Start colors in curses
|
||||||
|
curses.start_color()
|
||||||
|
curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_GREEN) # Neutral Land
|
||||||
|
curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLUE) # Neutral Sea
|
||||||
|
curses.init_pair(3, curses.COLOR_WHITE, curses.COLOR_GREEN) # Friendly Land
|
||||||
|
curses.init_pair(4, curses.COLOR_WHITE, curses.COLOR_BLUE) # Friendly Sea
|
||||||
|
curses.init_pair(5, curses.COLOR_RED, curses.COLOR_GREEN) # Enemy Land
|
||||||
|
curses.init_pair(6, curses.COLOR_RED, curses.COLOR_BLUE) # Enemy Sea
|
||||||
|
curses.init_pair(7, curses.COLOR_BLACK, curses.COLOR_BLACK) # Outside of the map
|
||||||
|
|
||||||
|
while (k != ord('q')):
|
||||||
|
# Initialization
|
||||||
|
stdscr.clear()
|
||||||
|
height, width = stdscr.getmaxyx()
|
||||||
|
|
||||||
|
if k == curses.KEY_DOWN:
|
||||||
|
center['y'] = center['y'] + 1
|
||||||
|
elif k == curses.KEY_UP:
|
||||||
|
center['y'] = center['y'] - 1
|
||||||
|
elif k == curses.KEY_RIGHT:
|
||||||
|
center['x'] = center['x'] + 1
|
||||||
|
elif k == curses.KEY_LEFT:
|
||||||
|
center['x'] = center['x'] - 1
|
||||||
|
|
||||||
|
for y in range(1,height):
|
||||||
|
for x in range(1,width):
|
||||||
|
if gamestate.terrain[x][y] == "l":
|
||||||
|
stdscr.addstr( y, x, " ", curses.color_pair(1) )
|
||||||
|
elif gamestate.terrain[x][y] == "w":
|
||||||
|
stdscr.addstr( y, x, " ", curses.color_pair(2) )
|
||||||
|
|
||||||
|
|
||||||
|
# Refresh the screen
|
||||||
|
stdscr.refresh()
|
||||||
|
|
||||||
|
# Wait for next input
|
||||||
|
k = stdscr.getch()
|
||||||
|
|
||||||
|
def main():
|
||||||
|
curses.wrapper(draw_map)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
16
experiments/make_map_animation.py
Normal file
16
experiments/make_map_animation.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from map import Map
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
slides = []
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
for x in range(1,100):
|
||||||
|
map = Map(sealevel=x, xoffset=0, yoffset=0)
|
||||||
|
map.generateMap()
|
||||||
|
# map.findCoast()
|
||||||
|
# map.generateCities()
|
||||||
|
# map.addCities()
|
||||||
|
#map.printWorld()
|
||||||
|
slides.append(map.saveWorld())
|
||||||
|
|
||||||
|
slides[0].save("zlevel_7.gif", save_all=True, append_images=slides[1:], optimize=True, duration=500, loop=0)
|
18
experiments/make_map_animation_lacunarity.py
Normal file
18
experiments/make_map_animation_lacunarity.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
from map import Map
|
||||||
|
# from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
slides = []
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
max_scale = 32
|
||||||
|
max_lacunarity = 100
|
||||||
|
width=150
|
||||||
|
height=50
|
||||||
|
for lacunarity in range(1,max_lacunarity):
|
||||||
|
lacunarity = lacunarity/100
|
||||||
|
print("Lacunarity: "+str(lacunarity))
|
||||||
|
map = Map(scale=32, base=1, width=width, height=height, lacunarity=lacunarity)
|
||||||
|
map.generateMap()
|
||||||
|
slides.append(map.saveWorld())
|
||||||
|
|
||||||
|
slides[0].save("zoom_base1_zoom"+str(max_scale)+"_lacunarity"+str(max_lacunarity)+"_width"+str(width)+"_height"+str(height)+".gif", save_all=True, append_images=slides[1:], optimize=True, duration=40, loop=0)
|
19
experiments/make_map_animation_shift.py
Normal file
19
experiments/make_map_animation_shift.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
from map import Map
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
slides = []
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
max_scale = 64
|
||||||
|
lacunarity = 1.5
|
||||||
|
for scale in range(32,max_scale):
|
||||||
|
print("Scale: "+str(scale))
|
||||||
|
map = Map(scale=scale, base=1, width=640, height=480, lacunarity=lacunarity)
|
||||||
|
map.generateMap()
|
||||||
|
# map.findCoast()
|
||||||
|
# map.generateCities()
|
||||||
|
# map.addCities()
|
||||||
|
#map.printWorld()
|
||||||
|
slides.append(map.saveWorld())
|
||||||
|
|
||||||
|
slides[0].save("zoom_base1_zoom"+str(max_scale)+"_lacunarity"+str(lacunarity)+".gif", save_all=True, append_images=slides[1:], optimize=True, duration=150, loop=0)
|
31
experiments/test.py
Normal file
31
experiments/test.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import curses
|
||||||
|
|
||||||
|
from state import State
|
||||||
|
|
||||||
|
k = 0
|
||||||
|
|
||||||
|
gamestate = State()
|
||||||
|
gamestate.load()
|
||||||
|
terrain = gamestate.terrain
|
||||||
|
|
||||||
|
def main(stdscr):
|
||||||
|
mypad = curses.newpad(62,62)
|
||||||
|
for y in range(0,62):
|
||||||
|
mypad.addstr( y, 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqerstuvwxyz1234567890")
|
||||||
|
|
||||||
|
mypad_pos = 0
|
||||||
|
mypad.refresh(mypad_pos, 0, 5, 5, 10, 30)
|
||||||
|
|
||||||
|
while (k != ord('q')):
|
||||||
|
mypad.refresh(mypad_pos, 0, 5, 5, 10, 30)
|
||||||
|
|
||||||
|
if k == curses.KEY_DOWN:
|
||||||
|
mypad_pos += 1
|
||||||
|
mypad.refresh(mypad_pos, 0, 5, 5, 10, 60)
|
||||||
|
elif k == curses.KEY_UP:
|
||||||
|
mypad_pos -= 1
|
||||||
|
mypad.refresh(mypad_pos, 0, 5, 5, 10, 60)
|
||||||
|
|
||||||
|
k = stdscr.getch()
|
||||||
|
|
||||||
|
curses.wrapper(main)
|
28
gen_map.py
Normal file
28
gen_map.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
from map import Map
|
||||||
|
import pickle
|
||||||
|
|
||||||
|
slides = []
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Generate the basic map.
|
||||||
|
map = Map()
|
||||||
|
map.generateMap()
|
||||||
|
|
||||||
|
# Add the cities
|
||||||
|
map.findCoast()
|
||||||
|
map.generateCities()
|
||||||
|
map.addCities()
|
||||||
|
|
||||||
|
# Print stuff or dump to image
|
||||||
|
#map.printWorld()
|
||||||
|
terrain, cities, coast, metadata = map.dumpMap()
|
||||||
|
gamestate = {}
|
||||||
|
gamestate['metadata'] = metadata
|
||||||
|
gamestate['terrain'] = terrain
|
||||||
|
gamestate['cities'] = cities
|
||||||
|
gamestate['coast'] = coast
|
||||||
|
gamestate['units'] = []
|
||||||
|
gamestate['fog'] = []
|
||||||
|
|
||||||
|
pickle.dump(gamestate, open("savegame.empyre_save","wb"))
|
||||||
|
#gamestate = pickle.load( open( "savegame.empyre", "rb" ) )
|
20
loadstate.py
Normal file
20
loadstate.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#from map import Map
|
||||||
|
from state import State
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
gamestate = State()
|
||||||
|
gamestate.load()
|
||||||
|
|
||||||
|
print(gamestate.metadata)
|
||||||
|
#print(gamestate.terrain)
|
||||||
|
#Map.printWorldExt(gamestate.terrain, gamestate.metadata)
|
||||||
|
|
||||||
|
for y in range(1,gamestate.metadata['height']+1):
|
||||||
|
for x in range(1,gamestate.metadata['width']+1):
|
||||||
|
if gamestate.terrain[x][y] == "c":
|
||||||
|
print('\x1b[1;37;42m' + '*' + '\x1b[0m', end='')
|
||||||
|
elif gamestate.terrain[x][y] == "l":
|
||||||
|
print('\x1b[1;37;42m' + ' ' + '\x1b[0m', end='')
|
||||||
|
else:
|
||||||
|
print('\x1b[1;37;44m' + ' ' + '\x1b[0m', end='')
|
||||||
|
print(" ")
|
59
location_test.py
Normal file
59
location_test.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import curses
|
||||||
|
|
||||||
|
# Import my own libraries
|
||||||
|
from state import State
|
||||||
|
gamestate = State()
|
||||||
|
gamestate.load()
|
||||||
|
|
||||||
|
from render import Render
|
||||||
|
|
||||||
|
# -- Initialize --
|
||||||
|
stdscr = curses.initscr()
|
||||||
|
curses.noecho()
|
||||||
|
curses.cbreak()
|
||||||
|
stdscr.keypad(1)
|
||||||
|
stdscr.notimeout(1)
|
||||||
|
|
||||||
|
# Clear and refresh the screen for a blank canvas
|
||||||
|
stdscr.clear()
|
||||||
|
stdscr.refresh()
|
||||||
|
|
||||||
|
height, width = stdscr.getmaxyx()
|
||||||
|
|
||||||
|
curses.start_color()
|
||||||
|
curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK) # Neutral Land
|
||||||
|
curses.init_pair(2, curses.COLOR_BLUE, curses.COLOR_BLACK) # Neutral Sea
|
||||||
|
curses.init_pair(3 , curses.COLOR_RED, curses.COLOR_BLACK) # Hostile
|
||||||
|
curses.init_pair(7, curses.COLOR_BLACK, curses.COLOR_BLACK) # Outside of the map
|
||||||
|
|
||||||
|
#stdscr = Render.renderScreen(stdscr, gamestate, 40, 12)
|
||||||
|
stdscr = Render.renderScreen(stdscr, gamestate, 75, 25)
|
||||||
|
|
||||||
|
k = 0
|
||||||
|
map_focus_x = round(gamestate.metadata['width']/2)
|
||||||
|
map_focus_y = round(gamestate.metadata['height']/2)
|
||||||
|
while (k != ord('q')):
|
||||||
|
|
||||||
|
if k == curses.KEY_DOWN:
|
||||||
|
map_focus_y = map_focus_y + 1
|
||||||
|
elif k == curses.KEY_UP:
|
||||||
|
map_focus_y = map_focus_y - 1
|
||||||
|
elif k == curses.KEY_RIGHT:
|
||||||
|
map_focus_x = map_focus_x + 1
|
||||||
|
elif k == curses.KEY_LEFT:
|
||||||
|
map_focus_x = map_focus_x - 1
|
||||||
|
|
||||||
|
map_focus_x = max(0, map_focus_x)
|
||||||
|
map_focus_x = min(gamestate.metadata['width'], map_focus_x)
|
||||||
|
|
||||||
|
map_focus_y = max(0, map_focus_y)
|
||||||
|
map_focus_y = min(gamestate.metadata['height'], map_focus_y)
|
||||||
|
|
||||||
|
stdscr = Render.renderScreen(stdscr, gamestate, map_focus_x, map_focus_y)
|
||||||
|
|
||||||
|
k = stdscr.getch()
|
||||||
|
|
||||||
|
stdscr.keypad(0)
|
||||||
|
curses.echo()
|
||||||
|
curses.nocbreak()
|
||||||
|
curses.endwin()
|
152
map.py
Normal file
152
map.py
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
import noise
|
||||||
|
import random
|
||||||
|
from collections import defaultdict
|
||||||
|
import math
|
||||||
|
|
||||||
|
class Map():
|
||||||
|
|
||||||
|
def __init__( self, width=150, height=50, sealevel=50, scale=32, base=random.randint(1,250), lacunarity=0.5+random.random(), octaves=50, persistence=0.5, xoffset=random.randint(1,10000), yoffset=random.randint(1,10000) ):
|
||||||
|
|
||||||
|
print("Initializing map")
|
||||||
|
|
||||||
|
# Dealing with basic params
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
self.sealevel = -0.37+((0.75/100)*sealevel)
|
||||||
|
self.scale = scale
|
||||||
|
self.base = base
|
||||||
|
self.octaves = octaves
|
||||||
|
self.persistence = persistence
|
||||||
|
self.lacunarity = lacunarity
|
||||||
|
self.xoffset = xoffset
|
||||||
|
self.yoffset = yoffset
|
||||||
|
|
||||||
|
# The master map we are going to need
|
||||||
|
self.map = defaultdict(dict)
|
||||||
|
self.coast = []
|
||||||
|
|
||||||
|
# All the required stuff to determine cities
|
||||||
|
self.cities = []
|
||||||
|
# self.num_cities = 50+(100-int(self.sealevel))
|
||||||
|
self.num_cities = 75
|
||||||
|
self.coast_percentage = 25
|
||||||
|
self.distance = 3
|
||||||
|
|
||||||
|
|
||||||
|
def generateMap(self):
|
||||||
|
print("Generating Map")
|
||||||
|
# Fill in the blanks with random stuff
|
||||||
|
for x in range(1,self.width+1):
|
||||||
|
for y in range(1,self.height+1):
|
||||||
|
area = noise.pnoise2( self.xoffset+x/self.scale, self.yoffset+y/(self.scale/3), octaves=self.octaves, persistence=self.persistence, lacunarity=self.lacunarity, repeatx=self.height, repeaty=self.width, base=self.base )
|
||||||
|
if area > self.sealevel:
|
||||||
|
self.map[x][y] = "l"
|
||||||
|
else:
|
||||||
|
self.map[x][y] = "w"
|
||||||
|
|
||||||
|
|
||||||
|
# Find coastal positions
|
||||||
|
def findCoast(self):
|
||||||
|
print("Finding coastal tiles")
|
||||||
|
# Should replace with a range()-loop
|
||||||
|
y = 1
|
||||||
|
|
||||||
|
while y <= self.height:
|
||||||
|
x = 1
|
||||||
|
while x <= self.width:
|
||||||
|
water = 0
|
||||||
|
if x !=1 and x!=self.width and y!=1 and y!=self.height and self.map[x][y]=="l":
|
||||||
|
if self.map[x-1][y-1]=="w":
|
||||||
|
water += 1
|
||||||
|
if self.map[x][y-1]=="w":
|
||||||
|
water += 1
|
||||||
|
if self.map[x+1][y-1]=="w":
|
||||||
|
water += 1
|
||||||
|
if self.map[x+1][y]=="w":
|
||||||
|
water += 1
|
||||||
|
if self.map[x+1][y+1]=="w":
|
||||||
|
water += 1
|
||||||
|
if self.map[x][y+1]=="w":
|
||||||
|
water += 1
|
||||||
|
if self.map[x-1][y+1]=="w":
|
||||||
|
water += 1
|
||||||
|
if self.map[x-1][y]=="w":
|
||||||
|
water += 1
|
||||||
|
if water >= 1:
|
||||||
|
coords = {}
|
||||||
|
coords['x'] = x
|
||||||
|
coords['y'] = y
|
||||||
|
self.coast.append(coords)
|
||||||
|
x+=1
|
||||||
|
y+=1
|
||||||
|
|
||||||
|
|
||||||
|
def generateCities(self):
|
||||||
|
print("Generate cities")
|
||||||
|
for round in range(0,self.num_cities):
|
||||||
|
if random.randint(1,100) < self.coast_percentage:
|
||||||
|
self.cities.append(random.choice(self.coast))
|
||||||
|
else:
|
||||||
|
found = 0
|
||||||
|
while found == 0:
|
||||||
|
randX = random.randint(1,self.width)
|
||||||
|
randY = random.randint(1,self.height)
|
||||||
|
if self.map[randX][randY]=="l" and self.noCityNear(self.distance,randX,randY):
|
||||||
|
found = 1
|
||||||
|
coords = {}
|
||||||
|
coords['x'] = randX
|
||||||
|
coords['y'] = randY
|
||||||
|
self.cities.append(coords)
|
||||||
|
|
||||||
|
|
||||||
|
def noCityNear(self,distance,x,y):
|
||||||
|
noCityNear = True
|
||||||
|
counter = 0
|
||||||
|
for city in self.cities:
|
||||||
|
#Lay-Z D-Bug: print( str(counter) +" x:"+ str( abs(city['x']-x) ) +"; y:"+ str( abs(city['y']-y) ) +";")
|
||||||
|
# This should be an OR, but this takes forever! So this is good enough.
|
||||||
|
if abs(city['x']-x)<self.distance and abs(city['y']-y)<self.distance:
|
||||||
|
noCityNear = False
|
||||||
|
counter+=1
|
||||||
|
return noCityNear
|
||||||
|
|
||||||
|
|
||||||
|
def calcDistance(self,city,x,y):
|
||||||
|
return math.ceil( math.sqrt( ((city['x']-x)**2)+((city['y']-y)**2) ) )
|
||||||
|
|
||||||
|
|
||||||
|
def addCities(self):
|
||||||
|
print("Adding cities to map")
|
||||||
|
for city in self.cities:
|
||||||
|
self.map[city['x']][city['y']] = "c"
|
||||||
|
|
||||||
|
|
||||||
|
# Print the world in its entirety
|
||||||
|
# Per column we print the entire row
|
||||||
|
def printWorld(self):
|
||||||
|
print("Printing map: num_cities:"+str(self.num_cities)+" base:"+str(self.base)+" Offset:"+str(self.xoffset)+"/"+str(self.yoffset))
|
||||||
|
for y in range(1,self.height+1):
|
||||||
|
for x in range(1,self.width+1):
|
||||||
|
if self.map[x][y] == "c":
|
||||||
|
print('\x1b[1;37;42m' + '*' + '\x1b[0m', end='')
|
||||||
|
elif self.map[x][y] == "l":
|
||||||
|
print('\x1b[1;37;42m' + ' ' + '\x1b[0m', end='')
|
||||||
|
else:
|
||||||
|
print('\x1b[1;37;44m' + ' ' + '\x1b[0m', end='')
|
||||||
|
print("")
|
||||||
|
|
||||||
|
# Dump the map that Python can work with
|
||||||
|
def dumpMap(self):
|
||||||
|
terrain = self.map
|
||||||
|
metadata = {}
|
||||||
|
metadata['width'] = self.width
|
||||||
|
metadata['height'] = self.height
|
||||||
|
metadata['coast_percentage'] = self.coast_percentage
|
||||||
|
metadata['scale'] = self.scale
|
||||||
|
metadata['base'] = self.base
|
||||||
|
metadata['octaves'] = self.octaves
|
||||||
|
metadata['persistence'] = self.persistence
|
||||||
|
metadata['lacunarity'] = self.lacunarity
|
||||||
|
metadata['xoffset'] = self.xoffset
|
||||||
|
metadata['yoffset'] = self.yoffset
|
||||||
|
return terrain, self.cities, self.coast, metadata
|
86
notes.txt
Normal file
86
notes.txt
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
The world is a rectangle 60 by 100 squares on a side. The world consists of sea (.), land (+), uncontrolled cities (*), computer-controlled cities (X), and cities that you control (O).
|
||||||
|
|
||||||
|
Starting options:
|
||||||
|
Enemy Start:
|
||||||
|
- Entrenched enemy (default)
|
||||||
|
- 1 vs 1 (second stage)
|
||||||
|
Fog of War: 0) 100% intel 1) knows map 2) Fog of War + sees units 3) Fog of War + blind without units
|
||||||
|
MapSize: x,y
|
||||||
|
Message Delay
|
||||||
|
# WaterPercentage
|
||||||
|
# Smoothness
|
||||||
|
|
||||||
|
|
||||||
|
Storing data
|
||||||
|
pickle-file:
|
||||||
|
Units:
|
||||||
|
Unit:
|
||||||
|
Type
|
||||||
|
Side
|
||||||
|
Location
|
||||||
|
Action
|
||||||
|
Order
|
||||||
|
Cities:
|
||||||
|
City:
|
||||||
|
Location
|
||||||
|
Side
|
||||||
|
Order
|
||||||
|
Stage
|
||||||
|
Terrain:
|
||||||
|
x
|
||||||
|
y
|
||||||
|
type
|
||||||
|
|
||||||
|
numpad keys:
|
||||||
|
49 t/m 57
|
||||||
|
|
||||||
|
Keys:
|
||||||
|
c: cities
|
||||||
|
p: pause
|
||||||
|
b: build
|
||||||
|
a: army
|
||||||
|
f: fighter
|
||||||
|
p: patrol boat
|
||||||
|
d: destoryer
|
||||||
|
s: submarine
|
||||||
|
t: troop transport
|
||||||
|
c: aircraft carrier
|
||||||
|
b: battleship
|
||||||
|
z: Satellite
|
||||||
|
u: units
|
||||||
|
direction: move/attack/load
|
||||||
|
u+l: unload (for transport/carrier)
|
||||||
|
s: entry/sleep
|
||||||
|
w: waypoint (tells unit to move to x position)
|
||||||
|
n: give AI x turns
|
||||||
|
g: give AI 1 turn
|
||||||
|
q: save and quit
|
||||||
|
l: log
|
||||||
|
|
||||||
|
sealevel: -0.37 = 0.38
|
||||||
|
|
||||||
|
-------------------------------
|
||||||
|
Layers:
|
||||||
|
Fog of War - Black
|
||||||
|
Fog of War - Unit-Intel
|
||||||
|
Units - Atmosphere
|
||||||
|
Cities
|
||||||
|
Units - Sky
|
||||||
|
Units - Group
|
||||||
|
Terrain
|
||||||
|
-------------------------------
|
||||||
|
# from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
# def saveWorldToImage(self):
|
||||||
|
# img = Image.new('RGB', (self.width,self.height))
|
||||||
|
# for y in range(1,self.height+1):
|
||||||
|
# for x in range(1,self.width+1):
|
||||||
|
# if self.map[x][y] == "c":
|
||||||
|
# img.putpixel( (x-1,y-1), (255,0,0) )
|
||||||
|
# elif self.map[x][y] == "l":
|
||||||
|
# img.putpixel( (x-1,y-1), (0,255,0) )
|
||||||
|
# else:
|
||||||
|
# img.putpixel( (x-1,y-1), (0,0,255) )
|
||||||
|
# d = ImageDraw.Draw(img)
|
||||||
|
# d.text( (1,1), "SL: "+str(self.sealevel))
|
||||||
|
# return img
|
114
render.py
Normal file
114
render.py
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
# Render the window
|
||||||
|
|
||||||
|
import curses
|
||||||
|
|
||||||
|
class Render():
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
print("Starting Render-Engine")
|
||||||
|
|
||||||
|
|
||||||
|
def renderScreen(stdscr, gamestate, centerx, centery):
|
||||||
|
|
||||||
|
# Calculate what to render
|
||||||
|
# Get screen y and x
|
||||||
|
height, width = stdscr.getmaxyx()
|
||||||
|
|
||||||
|
top_left_x = centerx - round(width/2)
|
||||||
|
top_left_y = centery - round(height/2)
|
||||||
|
|
||||||
|
xoffset = 0
|
||||||
|
yoffset = 0
|
||||||
|
if width > gamestate.metadata['width']:
|
||||||
|
xoffset = round( (width - gamestate.metadata['width'])/2 )
|
||||||
|
if height > gamestate.metadata['height']:
|
||||||
|
yoffset = round( (height-gamestate.metadata['height'])/2 )
|
||||||
|
|
||||||
|
|
||||||
|
# Draw the visible segment of the map
|
||||||
|
for y in range(1,height):
|
||||||
|
top_left_x = centerx - round(width/2)
|
||||||
|
for x in range(1,width-3):
|
||||||
|
if top_left_y <= 0 or top_left_y > gamestate.metadata['height'] or top_left_x <= 0 or top_left_x > gamestate.metadata['width']:
|
||||||
|
stdscr.addstr( y-1, x-1, " ", curses.color_pair(7))
|
||||||
|
elif gamestate.terrain[top_left_x][top_left_y] == "l":
|
||||||
|
stdscr.addstr( y-1, x-1, "+", curses.color_pair(1) )
|
||||||
|
elif gamestate.terrain[top_left_x][top_left_y] == "w":
|
||||||
|
stdscr.addstr( y-1, x-1, ".", curses.color_pair(2) )
|
||||||
|
elif gamestate.terrain[top_left_x][top_left_y] == "c":
|
||||||
|
stdscr.addstr( y-1, x-1, "*" )
|
||||||
|
top_left_x += 1
|
||||||
|
top_left_y += 1
|
||||||
|
|
||||||
|
|
||||||
|
##### Print the horizontal ruler at the bottom of the screen
|
||||||
|
xruler = ""
|
||||||
|
xrulery = 0
|
||||||
|
xrulerx = 0
|
||||||
|
xrulerx_offset = 0
|
||||||
|
|
||||||
|
|
||||||
|
if width > gamestate.metadata['width']:
|
||||||
|
xrulerx_offset = xoffset + 1
|
||||||
|
xrulerx = gamestate.metadata['width']
|
||||||
|
elif width < gamestate.metadata['width']:
|
||||||
|
xrulerx = width
|
||||||
|
else:
|
||||||
|
xrulerx = gamestate.metadata['width']
|
||||||
|
|
||||||
|
|
||||||
|
if gamestate.metadata['height']-1 < height-1:
|
||||||
|
xrulery = yoffset+gamestate.metadata['height']
|
||||||
|
else:
|
||||||
|
xrulery = height-1
|
||||||
|
|
||||||
|
|
||||||
|
skip = 0
|
||||||
|
if width > gamestate.metadata['width']:
|
||||||
|
xruler_start = 0
|
||||||
|
xruler_end = gamestate.metadata['width']
|
||||||
|
else:
|
||||||
|
xruler_start = centerx - round(width/2)
|
||||||
|
xruler_end = (xruler_start + width) - 4
|
||||||
|
|
||||||
|
for scale in range(xruler_start,xruler_end):
|
||||||
|
if skip != 0:
|
||||||
|
skip-=1
|
||||||
|
continue
|
||||||
|
if scale%10 == 0:
|
||||||
|
skip=len(str(scale))-1
|
||||||
|
xruler+=str(scale)
|
||||||
|
elif str(scale)[-1:]=="5":
|
||||||
|
xruler+="|"
|
||||||
|
else:
|
||||||
|
xruler+="."
|
||||||
|
stdscr.addstr( xrulery, xrulerx_offset, xruler )
|
||||||
|
|
||||||
|
|
||||||
|
##### Print the verticle ruler
|
||||||
|
yruler = centery - round(height/2)
|
||||||
|
yruler_offset = 0
|
||||||
|
yrulery = 1
|
||||||
|
#yruler = 0
|
||||||
|
yrulerx = 0
|
||||||
|
|
||||||
|
if width > gamestate.metadata['width']:
|
||||||
|
yrulerx = int((width - gamestate.metadata['width'])/2)+1+gamestate.metadata['width']
|
||||||
|
yruler_offset = (width - gamestate.metadata['width'])/2
|
||||||
|
elif gamestate.metadata['width'] < width-4:
|
||||||
|
yrulerx = gamestate.metadata['width']
|
||||||
|
else:
|
||||||
|
yrulerx = width-4
|
||||||
|
|
||||||
|
while yrulery < height-1 and yrulery-yruler_offset < gamestate.metadata['height'] and yruler <= gamestate.metadata['height']-1:
|
||||||
|
if yruler >= 0:
|
||||||
|
if yruler%5==0:
|
||||||
|
yruler_text = "{: >3}".format( yruler )
|
||||||
|
stdscr.addstr( yrulery, yrulerx, yruler_text )
|
||||||
|
else:
|
||||||
|
stdscr.addstr( yrulery, yrulerx, "{: >3}".format(".") )
|
||||||
|
yruler+=1
|
||||||
|
yrulery+=1
|
||||||
|
|
||||||
|
# Return stdscr asif nothing happened
|
||||||
|
return stdscr
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
noise
|
BIN
savegame.empyre_save
Normal file
BIN
savegame.empyre_save
Normal file
Binary file not shown.
21
state.py
Normal file
21
state.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# This loads/saves and manages the gamestate and can be used to query what is on the tiles
|
||||||
|
|
||||||
|
import pickle
|
||||||
|
|
||||||
|
class State():
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
#print("Loading state-engine")
|
||||||
|
self.gamestate = {}
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
self.gamestate = pickle.load( open( "savegame.empyre_save", "rb" ) )
|
||||||
|
self.metadata = self.gamestate['metadata']
|
||||||
|
self.terrain = self.gamestate['terrain']
|
||||||
|
self.cities = self.gamestate['cities']
|
||||||
|
self.coast = self.gamestate['coast']
|
||||||
|
self.units = self.gamestate['units']
|
||||||
|
self.fog = self.gamestate['fog']
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
pickle.dump(self.gamestate, open("savegame.empyre_save","wb"))
|
109
test.py
Normal file
109
test.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import curses
|
||||||
|
|
||||||
|
# Import my own libraries
|
||||||
|
from state import State
|
||||||
|
gamestate = State()
|
||||||
|
gamestate.load()
|
||||||
|
|
||||||
|
|
||||||
|
# Print (portion of the) map
|
||||||
|
#def fillMap(stdscr,gamestate):
|
||||||
|
# for y in range(1,height):
|
||||||
|
# for x in range(1,width-3):
|
||||||
|
# if y < 0 or y > gamestate.metadata['height'] or x < 0 or x > gamestate.metadata['width']:
|
||||||
|
# stdscr.addstr( y-1, x-1, " ", curses.color_pair(7))
|
||||||
|
# elif gamestate.terrain[x][y] == "l":
|
||||||
|
# stdscr.addstr( y-1, x-1, "+", curses.color_pair(1) )
|
||||||
|
# elif gamestate.terrain[x][y] == "w":
|
||||||
|
# stdscr.addstr( y-1, x-1, ".", curses.color_pair(2) )
|
||||||
|
# elif gamestate.terrain[x][y] == "c":
|
||||||
|
# stdscr.addstr( y-1, x-1, "O" )
|
||||||
|
# return stdscr
|
||||||
|
|
||||||
|
# -- Initialize --
|
||||||
|
stdscr = curses.initscr()
|
||||||
|
curses.noecho()
|
||||||
|
curses.cbreak()
|
||||||
|
stdscr.keypad(1)
|
||||||
|
stdscr.notimeout(1)
|
||||||
|
|
||||||
|
height, width = stdscr.getmaxyx()
|
||||||
|
|
||||||
|
curses.start_color()
|
||||||
|
curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK) # Neutral Land
|
||||||
|
curses.init_pair(2, curses.COLOR_BLUE, curses.COLOR_BLACK) # Neutral Sea
|
||||||
|
curses.init_pair(3 , curses.COLOR_RED, curses.COLOR_BLACK) # Hostile
|
||||||
|
curses.init_pair(7, curses.COLOR_BLACK, curses.COLOR_BLACK) # Outside of the map
|
||||||
|
|
||||||
|
|
||||||
|
# Print (portion of the) map
|
||||||
|
for y in range(1,height):
|
||||||
|
for x in range(1,width-3):
|
||||||
|
if y < 0 or y > gamestate.metadata['height'] or x < 0 or x > gamestate.metadata['width']:
|
||||||
|
stdscr.addstr( y-1, x-1, " ", curses.color_pair(7))
|
||||||
|
elif gamestate.terrain[x][y] == "l":
|
||||||
|
stdscr.addstr( y-1, x-1, "+", curses.color_pair(1) )
|
||||||
|
elif gamestate.terrain[x][y] == "w":
|
||||||
|
stdscr.addstr( y-1, x-1, ".", curses.color_pair(2) )
|
||||||
|
elif gamestate.terrain[x][y] == "c":
|
||||||
|
stdscr.addstr( y-1, x-1, "O" )
|
||||||
|
|
||||||
|
#stdscr = fillMap(stdscr, gamestate)
|
||||||
|
|
||||||
|
# Print horizontal ruler
|
||||||
|
xruler = ""
|
||||||
|
xrulery = 0
|
||||||
|
xrulerx = 0
|
||||||
|
|
||||||
|
if width < gamestate.metadata['width']:
|
||||||
|
xrulerx = width
|
||||||
|
else:
|
||||||
|
xrulerx = gamestate.metadata['width']
|
||||||
|
|
||||||
|
if gamestate.metadata['height']-1 < height-1:
|
||||||
|
xrulery = gamestate.metadata['height']-1
|
||||||
|
else:
|
||||||
|
xrulery = height-1
|
||||||
|
|
||||||
|
for scale in range(0,100):
|
||||||
|
xruler += "{:.<10}".format(scale*10)
|
||||||
|
if (xrulerx - 10) - len(xruler) < 6 :
|
||||||
|
xruler += str((scale+1)*10)
|
||||||
|
break
|
||||||
|
while len(xruler) < width-4 and len(xruler) < gamestate.metadata['width']:
|
||||||
|
xruler += "."
|
||||||
|
stdscr.addstr( xrulery, 0, xruler )
|
||||||
|
|
||||||
|
|
||||||
|
# Print the verticle ruler
|
||||||
|
yruler = 0
|
||||||
|
yrulerx = 0
|
||||||
|
|
||||||
|
if gamestate.metadata['width'] < width-4:
|
||||||
|
yrulerx = gamestate.metadata['width']
|
||||||
|
else:
|
||||||
|
yrulerx = width-4
|
||||||
|
|
||||||
|
while yruler < height-1 and yruler < gamestate.metadata['height']:
|
||||||
|
if yruler%5==0:
|
||||||
|
yruler_text = "{: >3}".format( yruler )
|
||||||
|
stdscr.addstr( yruler, yrulerx, yruler_text )
|
||||||
|
else:
|
||||||
|
stdscr.addstr( yruler, yrulerx, "{: >3}".format(".") )
|
||||||
|
yruler+=1
|
||||||
|
|
||||||
|
|
||||||
|
#stdscr.addstr( 1, 22, "a", curses.color_pair(3))
|
||||||
|
#stdscr.addstr( 5, 5, "p", curses.color_pair(3))
|
||||||
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# stay in this loop till the user presses 'q'
|
||||||
|
ch = stdscr.getch()
|
||||||
|
if ch == ord('q'):
|
||||||
|
break
|
||||||
|
|
||||||
|
stdscr.keypad(0)
|
||||||
|
curses.echo()
|
||||||
|
curses.nocbreak()
|
||||||
|
curses.endwin()
|
Loading…
x
Reference in New Issue
Block a user