Simple tower defense game ! Uses a lot of memory.
Very unoptimised. A better version is available at https://my.numworks.com/python/mathieu-croslacoste/castle_defence_v7
from math import * from ion import * from random import * from kandinsky import * from time import * can_place=False w=0 M=100 HP=100 map_select=1 pos_y=0 selection=0 wave_on="" frozen=False e_count=[] t_count=[] t_a_count=[] map=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,] letters=["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"] names=[] for i in range(120): if len(names)<26: names.append(str(letters[len(names)])) elif len(names)<351: a=len(names)%26 b=len(names)//26 names.append(str(letters[b]+letters[a])) letters.clear() class ennemy(): ennemy: __slots__ = ("lvl","og_level","ex","ey","heading","speed") def __init__(self,level,speed): global e_count e_count.append(self) self.lvl=level self.og_level=level self.ex=1 self.ey=34 self.heading=90 self.speed=speed def draw(self): r=0 g=0 b=0 if self.lvl==1: r=20 g=255 b=0 elif self.lvl==2: r=255 g=127 b=0 elif self.lvl==3: r=255 g=20 b=0 elif self.lvl==4: r=127 g=0 b=127 elif self.lvl==5: r=20 g=0 b=255 elif self.lvl==6: r=255 g=255 b=255 if self.lvl>=1: fill_rect(self.ex,self.ey,4,4,color(r,g,b)) def finished(self): global HP,e_count if self.lvl<=0:#dead? if self in e_count: self.remove_e() elif (self.ex>=246) and (self.ey>=166):#reached castle? HP-=(self.lvl*3) self.remove_e() redraw() return True def remove_e(self): global M,e_count e_count.remove(self) M+=self.og_level+3*self.speed-3+randint(0,2) u_s() def move(self): if self.finished(): if self.heading==90: if (not (get_pixel((self.ex-1),(self.ey-3))==color(130,90,5))): if (not (get_pixel((self.ex-1),(self.ey+7))==color(130,90,5))): self.ex+=self.speed else: self.heading=180 self.ey+=8 else: self.heading=0 self.ey-=8 elif self.heading==270: if (not (get_pixel((self.ex+1),(self.ey-3))==color(130,90,5))): if (not (get_pixel((self.ex+1),(self.ey+7))==color(130,90,5))): self.ex-=self.speed else: self.heading=180 self.ey+=8 self.ex-=2 else: self.heading=0 self.ey-=8 elif self.heading==0: if (not (get_pixel((self.ex-3),(self.ey+5))==color(130,90,5))): if (not (get_pixel((self.ex+7),(self.ey+5))==color(130,90,5))): self.ey-=self.speed else: self.heading=90 self.ex+=8 else: self.heading=270 self.ex-=8 elif self.heading==180: if (not (get_pixel((self.ex-5),(self.ey-1))==color(130,90,5))): if (not (get_pixel((self.ex+8),(self.ey-1))==color(130,90,5))): self.ey+=self.speed else: self.heading=90 self.ex+=8 else: self.heading=270 self.ex-=8 class t_attack: def __init__(self,x,y,damage,target,type): global t_a_count t_a_count.append(self) self.x=x self.y=y self.damage=damage self.target=target self._type=type def draw_attack(self): if self._type=="normal": r(self.x,self.y,3,3,110,110,110) elif self._type=="double": r(self.x,self.y,2,2,120,120,120) elif self._type=="fire": r(self.x,self.y,3,3,255,155,155) elif self._type=="ice": r(self.x,self.y,3,3,155,155,255) def move_attack(self): if self.x<self.target.ex: if self.y<self.target.ey: self.x+=4 self.y+=4 elif self.y>self.target.ey: self.x+=4 self.y-=4 else: self.x+=8 elif self.x>self.target.ex: if self.y<self.target.ey: self.x-=4 self.y+=4 elif self.y>self.target.ey: self.x-=4 self.y-=4 else: self.x-=8 elif self.y<self.target.ey: self.y+=8 elif self.y>self.target.ey: self.y-=8 hit_target(self) self.draw_attack() def hit_target(self): global t_a_count,frozen if (self.x-4<self.target.ex<self.x+8) and (self.y-4<self.target.ey<self.y+8): t_a_count.remove(self) self.target.lvl-=self.damage if self._type=="ice": frozen=True class t(): def __init__(self,x,y,dmg,rel,range,type): global t_count t_count.append(self) self.tx=x self.ty=y self.dmg=dmg self.rel=rel self.r_t=rel self.ran=range self.type=type self.level=1 if type=="normal": self.c=25 elif type=="double": self.c=60 elif type=="fire": self.c=130 elif type=="ice": self.c=350 def draw_t(self): if self.type=="normal": r((self.tx+1),(self.ty+1),6,6,70,70,70) r((self.tx+3),(self.ty+4),2,5,120,120,120) elif self.type=="double": r((self.tx+1),(self.ty+1),6,6,70,70,70) r((self.tx+1),(self.ty+4),2,4,120,120,120) r((self.tx+4),(self.ty+4),2,4,120,120,120) elif self.type=="fire": r((self.tx+1),(self.ty+1),6,6,200,50,15) r((self.tx+3),(self.ty+4),2,5,70,160,10) elif self.type=="ice": r((self.tx+1),(self.ty+1),6,6,80,80,180) r((self.tx+3),(self.ty+4),2,5,30,30,180) def do_t_attack(self): if self.r_t>=self.rel: e_name=0 for e in e_count: if ((self.tx+4-self.ran)<=e.ex<=(self.tx+4+self.ran)) and ((self.ty-4-self.ran)<=e.ey<=(self.ty-4+self.ran)): if e_name==0: e_name=e if e_name!=0: names[len(t_a_count)]=t_attack(self.tx,self.ty,self.dmg,e_name,self.type) self.r_t=0 else: self.r_t+=1 def upgrade(self,upg_type): global M if self.type=="normal": if M>=25 and self.level==1: self.level+=1 M-=25 self.c=60 self.rel-=4 self.ran+=12 elif M>=60 and self.level==2: self.level+=1 M-=60 self.c=150 self.dmg+=1 elif M>=150 and self.level==3: self.level+=1 M-=150 self.c=350 self.rel-=5 self.ran+=8 elif M>=350 and self.level==4: self.level+=1 M-=350 self.c="MAX" if upg_type==1: self.dmg+=5 self.rel+=12 self.ran+=32 else: self.dmg+=1 self.rel-=8 self.ran+=8 elif self.type=="double": if M>=60 and self.level==1: self.level+=1 M-=60 self.c=150 self.rel-=2 self.ran+=12 elif M>=150 and self.level==2: self.level+=1 M-=150 self.c=350 self.dmg+=1 elif M>=350 and self.level==3: self.level+=1 M-=350 self.c=850 self.rel-=3 self.ran+=8 elif M>=850 and self.level==4: self.level+=1 M-=850 self.c="MAX" if upg_type==1: self.dmg-=1 self.rel-=8 self.ran+=24 else: self.dmg+=4 self.ran+=8 elif self.type=="fire": if M>=130 and self.level==1: self.level+=1 M-=130 self.c=300 self.rel-=4 self.ran+=12 elif M>=300 and self.level==2: self.level+=1 M-=300 self.c=700 self.dmg+=2 elif M>=700 and self.level==3: self.level+=1 M-=700 self.c=2000 self.rel-=8 self.ran+=8 elif M>=2000 and self.level==4: self.level+=1 M-=2000 self.c="MAX" if upg_type==1: self.rel-=12 else: self.dmg+=1 self.rel-=4 self.ran+=16 elif self.type=="ice": if M>=350 and self.level==1: self.level+=1 M-=350 self.c=850 self.rel-=3 self.ran+=12 elif M>=850 and self.level==2: self.level+=1 M-=850 self.c=2000 self.dmg+=2 elif M>=2000 and self.level==3: self.level+=1 M-=2000 self.c=4500 self.rel-=5 self.ran+=16 elif M>=4500 and self.level==4: self.level+=1 M-=4500 self.c="MAX" if upg_type==1: self.rel-=9 self.ran+=16 self.dmg-=4 else: self.rel+=26 self.ran+=40 self.dmg+=10 map_selection(-1) def update_et(): global frozen if (not frozen) or (randint(1,2)==1): draw_path() for e in e_count: e.move() e.draw() frozen=False sleep(0.025) for i in t_count: i.do_t_attack() for a in t_a_count: a.move_attack() def z(nb,lvl,speed,a): for i in range(nb): names[(i+a)]=ennemy(lvl,speed) for i in range(9-3*speed): update_et() def start_w(): global w if w==0: w+=1 u_s() z(4,1,1,0) elif w==1: w+=1 u_s() z(3,1,1,0) z(3,2,1,2) elif w==2: w+=1 u_s() z(6,1,2,0) z(6,2,1,5) elif 30>w>2: w+=1 u_s() z(w//4+1+w//16,w//4,2,0) z(w//3+1+w//16,w//3,1,w//4+w//16) z(w//4+2+w//16,w//3+w%3,1,w//4+w//3+w//16*2) elif w>29: w+=1 u_s() z(w//8+w//16,w//5,2,0) z(w//4+w//16,w//4,2,w//4+w//16) z(w//3+1+w//16,w//3,1,w//4+w//3+w//16*2+1) z(w//4+w//16,w//3+w%3,1,w//4+w//3+w//4+w//16*3+2) def redraw(): r(0,0,320,200,0,0,0) u_s() draw_castle() draw_path() draw_button() for e in e_count: e.draw() for a in t_a_count: a.draw_attack() for t in t_count: t.draw_t() def map_selection(key): global map_select,map,can_place,selection,pos_y,wave_on upg="" redraw() if key==0: map_select-=1 if key==1: map_select-=40 if key==2: map_select+=40 if key==3: map_select+=1 if map_select<0: map_select+=len(map) if map_select>=len(map): map_select-=(len(map)) selection=map_select pos_y=1 while selection>40: selection-=40 pos_y+=8 if map[map_select]==0: can_place=True for i in t_count: if i.tx==selection*8 and i.ty==pos_y: can_place=False upg=i if can_place: r(selection*8+1,pos_y,6,6,200,200,200) t_costs() elif upg.level<4: r(selection*8+1,pos_y,6,6,160,160,255) init_disp() s("level "+str(upg.level)+". "+str(upg.c)+" to level up (toolbox)",0,205,200,100,50,0,0,0) elif upg.level==4: r(selection*8+1,pos_y,6,6,255,100,255) init_disp() s("level 4. "+str(upg.c)+" to max ([(] or [)])",0,205,200,100,50,0,0,0) elif upg.level==5: init_disp() s("level MAX",0,205,200,100,50,0,0,0) r(selection*8+1,pos_y,6,6,255,160,160) else: upg="" r(selection*8+1,pos_y,6,6,255,160,160) t_costs() elif map[map_select]==2: can_place=False r(selection*8+1,pos_y,6,6,200,255,200) else: can_place=False r(selection*8+1,pos_y,6,6,255,200,200) if key==4: if (wave_on=="") and (map[map_select]==2): wave_on="-in progress" start_w() elif upg!="": if key==16 and upg.level<4: upg.upgrade(0) sleep(0.5) elif (key==33 or key==34): upg.upgrade(key-32) sleep(0.5) else: sleep(0.038) def r(a,b,c,d,e,f,g): fill_rect(a,b,c,d,color(e,f,g)) def b(): r(0,0,320,230,0,0,0) def a(): while not keydown(4): pass while keydown(4): pass def draw_castle(): r(238,170,30,30,70,70,70) for i in range(0,30,10): r((239+i),163,7,7,70,70,70) for i in range(0,13,12): r((242+i),174,9,9,0,0,0) for i in range(4): r((248+i),(190-i),(10-2*i),10,149,69,49) def init_disp(): r(0,200,230,50,0,0,0) def s(a,b,c,d,e,f,g,h,i): draw_string(a,b,c,color(d,e,f),color(g,h,i)) def t_costs(): init_disp() s("50: 100: 200: 500:",0,205,200,100,50,0,0,0) r(33,205,12,12,70,70,70) r(37,211,4,9,120,120,120) r(93,205,12,12,70,70,70) r(95,212,3,8,120,120,120) r(100,212,3,8,120,120,120) r(153,205,12,12,200,50,15) r(157,211,4,10,200,100,50) r(213,205,12,12,80,80,180) r(217,211,4,10,30,30,180) def buy_t(key): global M,can_place total_levels=0 for i in t_count: total_levels+=i.level if len(t_count)*2>=total_levels and len(t_count)>10: s("upgrade your turrets first",25,50,200,10,25,0,0,0) sleep(2) redraw() else: if key==42: if M>=50 and can_place: place_t(selection*8,pos_y,1,42,56,"normal") M-=50 can_place=False elif key==43: if M>=100 and can_place: place_t(selection*8,pos_y,1,18,40,"double") M-=100 can_place=False elif key==44: if M>=200 and can_place: place_t(selection*8,pos_y,3,40,56,"fire") M-=200 can_place=False elif key==36: if M>=500 and can_place: place_t(selection*8,pos_y,3,40,72,"ice") M-=500 can_place=False redraw() sleep(0.2) def place_t(x,y,damage,reload,range,type): names[len(t_count)]=t(x,y,damage,reload,range,type) names[len(t_count)].draw_t() map_selection(-1) def draw_button(): r(296,0,24,24,140,140,140) for i in range(10): r(303+i,2+i,1,17-2*i,250,250,250) def draw_path(): r(0,32,112,8,130,90,5) r(104,40,8,32,130,90,5) r(32,72,80,8,130,90,5) r(24,72,8,64,130,90,5) r(32,128,152,8,130,90,5) r(176,56,8,72,130,90,5) r(184,56,72,8,130,90,5) r(248,64,8,104,130,90,5) def control(): for k in (42,43,44,36): if keydown(k): buy_t(k) for i in (0,1,2,3,4,16,33,34): if keydown(i): map_selection(i) def u_s(): s("Money "+str(M),200,0,200,100,50,0,0,0) s("Wave "+str(w)+wave_on,0,0,200,10,25,0,0,0) if (HP<100) and (HP>9): s("HP : "+str(HP),238,203,0,0,0,0,0,0) s("HP : "+str(HP),250,203,200,10,25,0,0,0) elif (HP<10): s("HP : "+str(HP),250,203,0,0,0,0,0,0) s("HP : "+str(HP),260,203,200,10,25,0,0,0) else: s("HP : "+str(HP),238,203,200,10,25,0,0,0) b() s("Castle Defence",87,80,200,10,25,0,0,0) sleep(0.4) s("Press [OK] to continue",52,125,200,10,25,0,0,0) a() b() s("Select with arrow keys",48,8,200,10,25,0,0,0) s("1,2,3 and 4 to place turrets",21,32,200,10,25,0,0,0) s("(1 cost 50,2 cost 100...)",32,48,200,10,25,0,0,0) s("Select the play button and",29,72,200,10,25,0,0,0) s("press [OK] to start next wave",17,88,200,10,25,0,0,0) s("Keep [OK] pressed during a wave",9,112,200,10,25,0,0,0) s("to see the turrets attacks",34,128,200,10,25,0,0,0) s("better, but the quality",52,144,200,10,25,0,0,0) s("may be affected",84,160,200,10,25,0,0,0) s("press toolbox/parenthesis to upg",0,184,200,10,25,0,0,0) s("Press [OK] to start",64,208,200,10,25,0,0,0) a() b() redraw() t_costs() while HP>0: while len(e_count)>0: update_et() control() if HP<=0: break wave_on="" for i in t_a_count: t_a_count.remove(i) redraw() u_s() control() update_et() b() s("GAME OVER",120,50,200,10,25,0,0,0) s("you lost at wave "+str(w),70,100,200,10,25,0,0,0)