From 12d0763a9535cacf4b8ea4a64ede022adbb2902e Mon Sep 17 00:00:00 2001 From: Pat Wick Date: Sat, 9 Mar 2024 21:25:51 -0500 Subject: [PATCH] added char attributes, enemies, combat I used the strategy/movement system for NPCs from Beast and added in some of my own mechanics for melee and projectile combat. A leveling system has also been established which modifies damage as the player levels up. Next order of business is level design, monster spawning, and game progression. --- __pycache__/dungeon.cpython-310.pyc | Bin 0 -> 750 bytes __pycache__/enemies.cpython-310.pyc | Bin 0 -> 1694 bytes __pycache__/map.cpython-310.pyc | Bin 0 -> 2181 bytes __pycache__/player.cpython-310.pyc | Bin 0 -> 2588 bytes __pycache__/projectile.cpython-310.pyc | Bin 0 -> 2092 bytes __pycache__/strategy.cpython-310.pyc | Bin 0 -> 2004 bytes __pycache__/wall.cpython-310.pyc | Bin 0 -> 473 bytes angband.py | 44 ++++++++++ dungeon.py | 27 ++++++ enemies.py | 73 ++++++++++++++++ map.py | 61 ++++++++++++++ player.py | 111 +++++++++++++++++++++++++ poetry.lock | 7 ++ projectile.py | 53 ++++++++++++ strategy.py | 57 +++++++++++++ wall.py | 7 ++ 16 files changed, 440 insertions(+) create mode 100644 __pycache__/dungeon.cpython-310.pyc create mode 100644 __pycache__/enemies.cpython-310.pyc create mode 100644 __pycache__/map.cpython-310.pyc create mode 100644 __pycache__/player.cpython-310.pyc create mode 100644 __pycache__/projectile.cpython-310.pyc create mode 100644 __pycache__/strategy.cpython-310.pyc create mode 100644 __pycache__/wall.cpython-310.pyc create mode 100644 angband.py create mode 100644 dungeon.py create mode 100644 enemies.py create mode 100644 map.py create mode 100644 player.py create mode 100644 poetry.lock create mode 100644 projectile.py create mode 100644 strategy.py create mode 100644 wall.py diff --git a/__pycache__/dungeon.cpython-310.pyc b/__pycache__/dungeon.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a3c522814012bcd0c890a64f3a1aa871f9771f4f GIT binary patch literal 750 zcmY*WJ#X7U4CS39>%+2P1RjzlODAWrV03KI25o?DUb+b=4yul|Ra-jyB*SQsE$N@= z)U|)<#&*h2Xr}UH3vejBcO>=1BPlf)L_qfQ#~+LxfWJ04HOj#ap*|z}2ofZFBs}mG zB>w~xC#U=i^C-F@)W3)jQYInglBJI1sY~#rllG*$VCas4*c(IYV}RZRyM@oQG$h|` z{i`&>PzVY?$M6C$x`yo~My=uvM(7?D?_VmUd#c}_%Rq*YkoILn z{r8Q3yQ>zcstJFxtI)h7N{|cMuE4Nqdp9jBdkujiB4YHcGz zm`I3H$=%xeu@Ku`w(j11QJI#aF7D9u5B|Q8&C~HW*g(_jP`3B zt@g&r)mjgzmv+b#ifzvB)+f}LL;<+$@QhgO#B9ulY|Mvj$oaoGY_;M?>{p|ry&3U literal 0 HcmV?d00001 diff --git a/__pycache__/enemies.cpython-310.pyc b/__pycache__/enemies.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..268a583b317153a51a8573e7b6cd63ff24b0008e GIT binary patch literal 1694 zcmbtU&2Aev5GJ|5k|oDc+bC_5Q<4G#8VhN2D$>+IQKTmah<%9=fLJdXd1dWSW>j|>~QKs@#ruiS*bO>dYA4i~MF^;AhV$xe50)-u%%kL318*s%2Lh*s4(35h|zB}-h zr~Fek2vnd#Ttn4BpH1UDhS>1Oi!br${^D!In9Q9IdZ+m-&LweC^O{Ng)jc-nyK`>B zA}^CF$+NjIZmGx5p@mv=23K(T_m}=*p6Y&aoWw`{G&)MMp*&8iLmB5v_tWF}UVoA$ z)sOuG@{x`!IgC(UXF5%Exm`?6C}n~QQj*mrMbhN67RJ1NzVSi0m?P%mwBerOOU*~D zW+Q$Lb8{r%ekD+HYW_-`h#F;*o{1CZ#H|Ic-icp3wbx~}Tl-!19JQshI`P_7;*5_R zvZBz!2w8oA_FwyFjFXQ5J#g5;FJaBjIJYDbQ9W-LIL2c9RsLq~(@DB*f>f7fG}OI@ z*{CLv$!wAyXfR$`Xsv)s%W`S14s|6_F{|XkRA$H!>QqssjiWPV#9?7tplzL4t$6^O z-6 zUVnGqpcGL|Qktg3npKlAy|<)%F^R_Sb{g?v1W{aRfN#m8uXLowQ|O`qR|#$tkoz^D z;J`!haW3hfLgr#v^n{}2*u6_{15hDQg+GZZ!=Eguc=i|M;)9Y|uW)GKE>M}n20@$P zA}AXVMSF|BcMxVRH2(jk2w$M?c^Lp*wVC^yF1Fz-e4RJo8ZIj?C>on}pez90NBD+- zXoDLBHwpd|6tVXmeZPY+Yg14cIRd+Lal*dYf4Pg=)*LksAn8&z%S(HUz}{jz8}=64 z)3CSLerEi=B2ie;d~ZQn-2ZIef1)rg?^jl)KZ*L__makneYi(9FXQxQ+O(W*y>s|6 zwElpn?$b$2D@nUO--Klacxi`Iut~P}n`p7T18J>g^?i;^_+WLX9#RV_Lxe51>1}p9 F-M1TEP0;`V literal 0 HcmV?d00001 diff --git a/__pycache__/map.cpython-310.pyc b/__pycache__/map.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0f1d3906f60fb0fcd14e352b2e53684c49123563 GIT binary patch literal 2181 zcmah~TW=dh6rP#AczsJ#w@pmM#RXAn3F4v(ghUjOir_6mq!N-vWNkbfXOms;W_ClG zXe}YNqUj_5AbreV+Epa_jq3FZ!_#(t^M1D( z`;{iMkHF+hv}6~ZWReFgwk1gzRx(>#+EInb} zvUFq_wjwLC3R{&mS%zd{>{r+kM?1FO!= zsv*r{pR`W7w3_U((7Vm247=@O_a&c|iOg7LnTcjCGhiugyc8G_YNBmYU^meX5ZabK z;u)80NBklV#3noEiol$+bCHYHdpY-&gSqbh{JgUpgaVOE%1}HABFKcCH@Zz=O#OOXFGD0?0ItF zC97*e)OUkq9fQf( zp(w+Oq<$$gdDR~dJ=N2|C@(XR8h|7IHHEs3^*KnSiy25~>^Z8s3~+lK@C2Xm8N;s$Ihf@diCbc dS{TX0z+0!!fDWt1YEUZu9O0B5$EnsD{{j0bq&NTo literal 0 HcmV?d00001 diff --git a/__pycache__/player.cpython-310.pyc b/__pycache__/player.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..85cbfa9f02111cfce03b506a45e62fb4de19c352 GIT binary patch literal 2588 zcma)8UvCpf5Wn5~i$VUZBe0=LLmhNO%YI`T9r;0?!4s?ZoN39hX_RE#V0Fxh33ZyyFS)k=3pp zV6W9?x_LvXZ0DXF-q?_70fBQn>Pw8l1C{k;w}=zjCEeqVV{#omzYij<4ii>~3)Zm( z?>NHlxWd6XZl{Ls3s2OZTb;V_MIB=x0x^YgN;E_hV?#`f6BwIf2KPFty$4A&luCO8 zGafJ;@q()w21UHChOPsC(uk)!-9*oS1u0o+g;r_rvl0BW#nr6fkf8VM(%$0CO6SL` zn5px^d2Q7f?yHiL8(SWqg1my2Lzl0@{_h#l6B2ij8`?gb>Km`+OBDTkmWF( zr8?+FgSd#2co!DBS%MS1F5NQJ_3mbbYvOj=%?A?4dLrsa8?x%iC#Oe7ZcSpcifcip$mO zmj*-ahhdEMFgyio`3E2#Z!nKF@FVK+fHk-W9wR7?9_9htJyD@*X=0&EZkRNJ4|%}A z=Ql8bNd=p)OV$IFdVCJ4g}`1et$iDFNAN|`a%r3=4zM3fFwR@+yksN3$4johEP2mU zUzOakdbN`6`@$KqUR}7StS^AtuqLcWNZq4e1po5{oDWT$^vv0_VR@>wN2UxQk-Sw! zRm7xBl|1x9H4D;in5gKfVq2wQy4_!sN}a)ierrP(Ap)5eaCA7qLKV)sh!vFsV8atK z63I~W&4E67v}J7=rU;liO9zopbv+WIve$OhIg&UOQtg^EbTE!HN{j(WMb49+7ZpX+ z-C6>l&w&JNhFxF|LVAule>vP?m+Wb_+Z>0r((V$#CykyzBF77_V1Q<35XCdV4rf|*eBUSC8Ih5xQy+~|Fkc0qOmWi$_$|6;RfT76NK7R zt8K3Rdn-SN_gB7stn0)*ynFl3V@0ksKxp%Wf6yvq_>fL^-1`2>s`hBd4-eEuvv35T zHm~>#kiTTDc5R&GCgSfwsQoMr*Rn_n080(SA`AQ3Q>pzp4`qK)4Am!O(yMS#-;%?; zP}!DLAJS&_i)KUJNafBE>{?hj28o$X)W<}IhdZxeJ*WEw$Z*Pd-(){=$a@x0HF!h9uqS(>9-=B;j&w$>ynJEhOk5~_D!=DDey>Rp_m-UmTZMWL74mZ=!0jq$Z{l=_I& zT8D&^MbZC&C+PV!NW)|aJ>B`+VY{>ArydK*8?QY4bW#z(E36UTxoDYJHjo71s~5HT zszCw%9?Tu)eI6q5C$-{@3nP=Mp5(9JnVuWcoe6;rz XMKV+T{HxW=t}%!z2i52sH_QJ8f*VuU literal 0 HcmV?d00001 diff --git a/__pycache__/projectile.cpython-310.pyc b/__pycache__/projectile.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..01968ae0d71c81cede15a344ed1e998abbb53afe GIT binary patch literal 2092 zcmZuyOK%%D5GJ_~tz_A8;>50-pkR|0=@zbpB9|V5Hb{Y_xd?@mlMsMdEoo`xeW=`( zRSD};^E(Rrn7_2wo^t3PNDHJhTK zfrGSfN!GWeCG9t)??^|w@O5QFdhl(?rfk92lUuS4-=^FKLpxRLSDlSjSVXa^=(o>8 z2d-Q;)Y0vqq36dSN?H;@N(Pda7D!gw7nY=#bZkp@%JkPI8B=MU5q($Mu36tjbPO>p*18A!ds_N# zd#~v(s4I*uWjne1tjT zzsk$|FevHRAiNJ{1+wr4;Ku+x#AKOgtY<>xTh&%E)u~9Q$v|mCZv7=(@s_QhblvMF zA|mkESFkfj%I$)y_J_so4L4VtLiBCfY*5f&!_Rx5l`-kbA7d`m!+!1SCqh1>#VTNG1ZsHco5HmdA>Rs z@HongBOqE7j(8HxSC@oYS_DANh0+-qOO>&hOyeS&#Hw}*+^fABMrT0OrI8I+UZlqB zrz*$`j(&kD#Zz^rG`JFHGe`lgU=O?#Y+St+GGk!!V&zS+zI-)j!0f?4#Qy)k)wgRn zO&K#ZbxkPqYuM_~0FrN@=U7DB4V!w1E8oC%WdI7+Dwdz{5sS6K7y&nxo%U*54`AY& z)oK^sEMo-)GX@NxNI!y2Ir7A2i@O`fukVAz#?pz^TZpP9M3TuVTqLTt5Wh`>xL(n_ zX!H=p9TdoLjpQ}&)elj_QobQDKQ%HJdyeNlVpE6*^IG1XXScV^Y7a7~1>DnF2O-ty avsu`<%G_-7-Fsa7_alZU$I!INE%qNOkNZ^s literal 0 HcmV?d00001 diff --git a/__pycache__/strategy.cpython-310.pyc b/__pycache__/strategy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..782e5e8d50ec531b1cf97cd77d0d5639a40ce3b7 GIT binary patch literal 2004 zcmaJ?TW{k;6!wfA$4S%c0^N&PydY65tu|Z16GCVucmmW1mZudcay`?;+r*O{Pd809 zmXOLbzoF%gzvNe*R){}<5am0QOVbK)G*{0YpYxsXd{OJ`Z4b|b)*tfcrsw@ei`9o? z@eHk`PI!V1y%BrCnAi6N|AoEa!WY3$-V0weM2ImEO%Y*ih?Zz$48@x0U~G!@=U%e$ z23EX;)nPVJc_xz};hJIV4Rx6N7~IBU{|XQ0!D2rnhZYaHPH(wV9wMitrsW3!5E!!~z48`@~sJK|N#a@)G+l^z#iwuz@pWemIo9k$Nr5I-HrQ*=fzDH5aF7 z)4Eg0$?~JWdU^+N{Q0aqP$StLPx9=zJ4%o9qTie3X3)!&kloQF+wYzfx%s#|*6Jmk z?2!}Q(&*I4{`ARss@GtqLGZqXF5&@;+;0ngoADn5=1$zm3gwWR%gTLBjAxOVb6#=F z^_pRppR?zn5-{dxUteRa(?Y1x9O78Zv6dy^gwsd>#ZIWF#VYXek;aV$hzDQ_Ijo5! ziLWD?x6suM2b}|D*4?4qwb>UPuG`os=|bBD8C>bNvA7Xfh>a!PKElFLi&ws7pjJ>d z5NKfeUGJP>*04U!c0EU>-xpz;fsFS?X)#ERK`a8iN{dYH%_32STt+jCR^ftf$9TT` zubV=ana&R-ScxMGi>n6n!rZo|3V@pBU~pgO;&D8|XJkB8CvgV1R58R06%Ulo&s1U3 zA=XF_lA}$Y(eiOzDB~OxdD>S6?LBd8)VH4=mPuIi@l&+@nxA5vqMc$s-M^iOXyNlN zKrIR8D2&)$rr*W%MhZ5tL3DK7I>m%4Ua(8{l2zRBInR95e_(yo|HG=`k`z`=+dz^c z)Vr&E+q5lL|83*jHW!v^O}@Oz{pood}e#ssNDaQ4X} zrE_vl26;A!C;4y~XQ;Y38>&)5H9%U*%XpYhrLM!-=tS-S5N$7IgH)qH{mp3WcuetY z$g)?5rP4-umAj%Z)+EY9_e>dpP! zE|Gf!|9gv^POuM>mcnfl-7}ZT4}EQ<&Nd#Gb}Elt4{H=0qKd)AgfmWutgFI@yLiOFZ+fJKc=mhy Kvg4xKG5G=SYGnEV literal 0 HcmV?d00001 diff --git a/angband.py b/angband.py new file mode 100644 index 0000000..4a15517 --- /dev/null +++ b/angband.py @@ -0,0 +1,44 @@ +from retro.game import Game +from player import Player +from dungeon import Dungeon +from random import sample +from wall import Wall +from map import ( + board_edges, + inner_board, + level_one, + random_empty_position +) +from enemies import ( + Orc, + Rat, + Spider +) + +print("Welcome to AngBAD (a poor representation of Angband)!\n") + +race = input("Choose your race (Human, Elf, Dwarf): ").capitalize() +while race not in ["Human", "Elf", "Dwarf"]: + print("Invalid race. Please choose Human, Elf, or Dwarf.") + race = input("Choose your race (Human, Elf, Dwarf): ").capitalize() + +class_ = input("Choose your class (Warrior, Mage, Rogue): ").capitalize() +while class_ not in ["Warrior", "Mage", "Rogue"]: + print("Invalid class. Please choose Warrior, Mage, or Rogue.") + class_ = input("Choose your class (Warrior, Mage, Rogue): ").capitalize() + +print(f"\nYou've chosen to play as a {race} {class_}.") +input("Press Enter to continue. Good luck!") + +board_size = (50,25) +x,y = board_size + +walls = [Wall(position) for position in board_edges(board_size)] +level = [Wall(position) for position in level_one(board_size)] +game = Game(walls + level, {"Race":race, "Class":class_,}, board_size = board_size) +game.add_agent(Player((x//2,y//2),race,class_)) +game.add_agent(Orc(random_empty_position(game))) +game.add_agent(Rat(random_empty_position(game))) +game.add_agent(Spider(random_empty_position(game))) + +game.play() \ No newline at end of file diff --git a/dungeon.py b/dungeon.py new file mode 100644 index 0000000..585f823 --- /dev/null +++ b/dungeon.py @@ -0,0 +1,27 @@ +# dungeon.py +# ------------ +# By Pat Wick +# This module defines a dungeon generation algorithm. I +# still need to figure out what that might actually mean + +class Dungeon: + board_size = (10,10) + board_width = 10 + board_height = 10 + position = (0,0) + dungeon_map = [["."] * board_width] * board_height + + + for row in range(board_height): + for col in range(board_width): + if row == 0 or row == board_height-1: + dungeon_map[row][col] = "#" + else: + if col == 0 or col == board_width-1: + dungeon_map[row][col] = "#" + else: + dungeon_map[row][col] = "." + + def __init__(self, position): + self.position = position + self.name = "dungeon" \ No newline at end of file diff --git a/enemies.py b/enemies.py new file mode 100644 index 0000000..a6dd311 --- /dev/null +++ b/enemies.py @@ -0,0 +1,73 @@ +from strategy import ( + random_move, + move_toward_player, +) + +class Orc: + character = "O" + hp = 20 + deadly = True + speed = 25 + + def __init__(self,position): + self.position = position + + def play_turn(self, game): + if game.turn_number % self.speed == 0: + move = move_toward_player(self.position, game) + if move: + x, y = self.position + dx, dy = move + self.position = (x + dx, y + dy) + if self.position == game.get_agent_by_name("player").position: + game.state['message'] = "Yum." + game.end() + + if self.hp <= 0: + game.remove_agent(self) + +class Rat: + character = "R" + hp = 2 + deadly = True + speed = 15 + + def __init__(self, position): + self.position = position + + def play_turn(self, game): + if game.turn_number % self.speed == 0: + move = random_move(self.position, game) + if move: + x, y = self.position + dx, dy = move + self.position = (x + dx, y + dy) + if self.position == game.get_agent_by_name("player").position: + game.state['message'] = "Eep." + game.end() + + if self.hp <= 0: + game.remove_agent(self) + +class Spider: + character = "S" + hp = 5 + deadly = True + speed = 5 + + def __init__(self,position): + self.position = position + + def play_turn(self, game): + if game.turn_number % self.speed == 0: + move = random_move(self.position, game) + if move: + x, y = self.position + dx, dy = move + self.position = (x + dx, y + dy) + if self.position == game.get_agent_by_name("player").position: + game.state['message'] = "Hsssss." + game.end() + + if self.hp <= 0: + game.remove_agent(self) \ No newline at end of file diff --git a/map.py b/map.py new file mode 100644 index 0000000..89597ad --- /dev/null +++ b/map.py @@ -0,0 +1,61 @@ +from retro.game import Game +from random import sample +from player import Player +from wall import Wall +from random import randint + +def board_edges(board_size): + x,y = board_size + positions = [] + top = [(i,0) for i in range(x)] + bottom = [(i,y-1) for i in range(x)] + left = [(0,j) for j in range(1,y-1)] + right = [(x-1,j) for j in range(1,y-1)] + return top + bottom + left + right + +def inner_board(board_size): + x,y = board_size + positions = [] + for i in range(1,x-1): + for j in range(1,y-1): + positions.append((i,j)) + return positions + +def random_empty_position(game): + """Returns a random empty position. + """ + agents_by_position = game.get_agents_by_position() + while True: + x, y = game.board_size + i = randint(1, x-2) + j = randint(1, y-2) + if not agents_by_position[(i,j)]: + return (i,j) + +def level_one(board_size): + x,y = board_size + positions = [] + for i in range(1,x-1): + for j in range(1,y//4): + if i <= x // 4 or i >= x - (x // 4): + positions.append((i,j)) + for i in range(1,x//4): + for j in range((y - (y // 4)), y-1): + positions.append((i,j)) + + # for i in range(1,x-1): + # for j in range(1,y-1): + # if i >=4 and i <= 7 or i >= 13 and i <= 16: + # if j >= 4 and j <= 7 or j >= 13 and j <= 16: + # positions.append((i,j)) + return positions + +def level_two(board_size): + x,y = board_size + positions = [] + for i in range(1,x-1): + for j in range(1,y-1): + if i >=4 and i <= 7 or i >= 13 and i <= 16: + if j >= 4 and j <= 7 or j >= 13 and j <= 16: + positions.append((i,j)) + return positions \ No newline at end of file diff --git a/player.py b/player.py new file mode 100644 index 0000000..d6bfcc5 --- /dev/null +++ b/player.py @@ -0,0 +1,111 @@ +# player.py +# ------------ +# By Pat Wick +# This module defines a player agent class. This is intended +# to be used in an implementation of an adventure game but could +# generally be adapted for other player character uses. + +from retro.agent import ArrowKeyAgent +from retro.game import Game +from projectile import Projectile + +class Player: + name = "player" + level = 1 + xp = 0 + direction = (1,0) + class_ = "" + speed = 0 + damage = 0 + + def __init__(self, position, race, class_): + """Class and race will determine player stats and abilities.""" + self.position = position + self.race = race + self.class_ = class_ + if class_.capitalize() == "Warrior": + self.color = "red" + self.class_ == class_ + elif class_.capitalize() == "Rogue": + self.color = "green" + self.class_ == class_ + else: + self.color = "blue" + self.class_ == class_ + + if race.capitalize() == "Human": + self.character = "H" + self.speed = 3 + self.damage = int(2 + (self.level / 3)) + elif race.capitalize() == "Elf": + self.character = "E" + self.speed = 1 + self.damage = int(1 + (self.level / 4)) + else: + self.character = "D" + self.speed = 6 + self.damage = int(3 + (self.level / 2)) + + def attack(self,game): + if self.class_ == "Warrior": + if game.turn_number % self.speed == 0: + agent = self.get_agent_in_position((self.position[0] + self.direction[0],self.position[1] + self.direction[1]),game) + if agent: + if agent.deadly: + agent.hp -= game.get_agent_by_name("player").damage * 2 + else: + projectile = Projectile((self.position[0] + self.direction[0],self.position[1] + self.direction[1]), self.direction, self.speed, game) + game.add_agent(projectile) + #print("pew pew pew") + + def handle_keystroke(self, keystroke, game): + x, y = self.position + if keystroke.name in ("KEY_LEFT", "KEY_RIGHT"): + if keystroke.name == "KEY_LEFT": + new_position = (x - 1, y) + self.direction = (-1,0) + else: + new_position = (x + 1, y) + self.direction = (1,0) + if game.on_board(new_position): + self.try_to_move(new_position,game) + if game.is_empty(new_position): + self.position = new_position + + if keystroke.name in ("KEY_DOWN", "KEY_UP"): + if keystroke.name == "KEY_DOWN": + new_position = (x, y + 1) + self.direction = (0,1) + else: + new_position = (x, y - 1) + self.direction = (0,-1) + if game.on_board(new_position): + self.try_to_move(new_position,game) + if game.is_empty(new_position): + self.position = new_position + + if keystroke == " ": + self.attack(game) + + def try_to_move(self, position, game): + agent = self.get_agent_in_position(position,game) + if agent: + if agent.deadly: + game.state['message'] = "Monsters can be deadly..." + game.end() + + + def get_agent_in_position(self, position, game): + + agents = game.get_agents_by_position()[position] + if agents: + return agents[0] + + def level_up(self): + xpToLevel = (self.level + self.level - 1) * 30 + if self.xp >= xpToLevel: + self.xp -= xpToLevel + self.level += 1 + + def play_turn(self,game): + self.level_up() \ No newline at end of file diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..ddb1526 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +package = [] + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "53f2eabc9c26446fbcc00d348c47878e118afc2054778c3c803a0a8028af27d9" diff --git a/projectile.py b/projectile.py new file mode 100644 index 0000000..2c7c749 --- /dev/null +++ b/projectile.py @@ -0,0 +1,53 @@ +from retro.game import Game + +class Projectile: + character = "*" + deadly = False + + def __init__(self, position, direction, speed, game): + self.position = position + self.direction = direction + self.speed = speed + if game.get_agent_by_name("player").class_ == "Rogue": + if self.direction in [(1,0), (-1,0)]: + self.character = "-" + elif self.direction in [(0,1), (0,-1)]: + self.character = "|" + + def move(self, game): + """Try to move in direction set by player when launched. If blocked, + disappear.""" + dx, dy = self.direction + new_position = (self.position[0] + dx, self.position[1] + dy) + if game.on_board(new_position): + if game.is_empty(new_position): + self.position = new_position + else: + agent = self.get_agent_in_position(new_position,game) + if agent: + if agent.deadly: + agent.hp -= game.get_agent_by_name("player").damage + game.remove_agent(self) + else: + game.remove_agent(self) + else: + game.remove_agent(self) + + def play_turn(self,game): + if game.turn_number % self.speed == 0: + self.move(game) + + def get_agent_in_position(self, position, game): + """Returns an agent at the position, or returns None. + game.get_agents_by_position always returns a list, which may + contain zero, one, or multiple agents at the given position. + In the Beast game, we never allow more than one agent to be in + a position. + """ + agents = game.get_agents_by_position()[position] + if agents: + return agents[0] + + def handle_collision(self, game): + # need to fix this at some point + pass \ No newline at end of file diff --git a/strategy.py b/strategy.py new file mode 100644 index 0000000..61074e3 --- /dev/null +++ b/strategy.py @@ -0,0 +1,57 @@ +from random import choice + +direction_vectors = [(0, 1), (1, 0), (0, -1), (-1, 0)] + +def possible_moves(position, game): + "Returns a list of vectors to empty spaces" + agents_by_position = game.get_agents_by_position() + possible_moves = [] + for vector in direction_vectors: + x, y = position + dx, dy = vector + new_position = (x + dx, y + dy) + if not agents_by_position[new_position]: + possible_moves.append(vector) + return possible_moves + +def random_move(position, game): + "Returns a random vector representing a move to an empty space from position" + moves = possible_moves(position, game) + if moves: + return choice(moves) + +def distance(p0, p1): + """Returns the 'manhattan distance' from one position to another + The 'manhattan distance' describes the distance from one point to another + on a city grid, where you can only go horizontally and vertically, not + diagonally. + """ + x0, y0 = p0 + x1, y1 = p1 + return abs(x1 - x0) + abs(y1 - y0) + +def move_toward_player(position, game): + "Returns a move which will come closest to the player" + player_position = game.get_agent_by_name("player").position + moves = possible_moves(position, game) + moves_with_distance = [] + for vector in moves: + x, y = position + dx, dy = vector + new_position = (x + dx, y + dy) + distance_to_player = distance(new_position, player_position) + moves_with_distance.append((distance_to_player, vector)) + if moves_with_distance: + shortest_distance, best_move = sorted(moves_with_distance)[0] + return best_move + +def move_to_player(position, game): + player_position = game.get_agent_by_name("player").position + for vector in direction_vectors: + x, y = position + dx, dy = vector + new_position = (x + dx, y + dy) + if new_position == player_position: + return vector + + diff --git a/wall.py b/wall.py new file mode 100644 index 0000000..7041db8 --- /dev/null +++ b/wall.py @@ -0,0 +1,7 @@ +class Wall: + #name = "wall" + character = "█" + deadly = False + + def __init__(self,position): + self.position = position \ No newline at end of file