0 D$404mNJN…L04e$ŠFHuqaY}ĪŅ},…•”mŖ,ŅŖ™mĀŹŚŌ^ŽīÖ š’’’’’’š’īž’’2Tv˜ŗÜžļĶ«‰gE#2Tv˜ŗÜž2Tv˜ŗÜžŅæF–ŽĪ9’,ęĮcÉY!ŹŻī’ß«X4"2d—BA #ƒźœżĪżļĖżŽCewV#2„ĖĶ*!"ŗHČ’^SČ™‰U†ˆUe’’0t™ŗÜŻĶ«‰wwˆ™x ĒŻž®5¦«©«6„žŽĶ'żąąžéžéžéžįéļžéžłļžŸłŸ  0 Ŗ11£33wŖ §sŖ:3Ŗz0ĄtĄąąąŽąķąķŽąąąą šģĒĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢafaffaffffffa±»±±±±»±ff»±±  """""""" ""ff`  """"ffff`ffff`€ˆ€ų’ˆ€’’€’’€ų’ˆ€ˆ€ų’ˆ€ˆ’Dō@”DD™ID”DDDD@DŠ ąŻŠŻŻł ł  ąļžž éž™éžžī™™™ą ™ī™īą™ ą ą™ éīąąąąī1§0   Ŗz1   @wš@÷Ą ĢÜP\d G’äļĢąŃįą ąĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢ»±±±»µ°»  """""""" """" UUUU^^åååU^^UUUUUUõ’’UUUą@ą@äąNīąīąžļžļą™ é™DžžDDé D’ŻßßŻŻŻšżżŠŻŻšżŻŠŻßżŻŻ  ŻŻ Ÿ / ¤ōō `  šw÷š0šŸ?  ™ š   łó ł JŖ @Ŗ @  @D@õPõ@@UD@@š0 !"@B DBO>"""!"@"/$/@P_@UšUUwuwwu§wqwww3> ń ąōī@3faf`f ī žAffš00ć013O1¤°° ™€™(˜š"3" ")@ ‰@ (ų#B!"QQšUīUP@Qń^EQEE@@@`@@oŖŖ® Ŗ  ŖŖ:£ōōō’ō’ō’Ŗō’Ŗō@śššŖšąźšŖ šŖŖš ŖŖŖ ŖzzwšŸ’Ÿš’š’ ŸŸ’™’ł’O’    ąą ž  ņą" Ģ€ ŸaĄ’š’f’šöof`öf’’’oö’’ffföföoöö :ŖŖŖŖ33ŖŖ   J £DCJJJ@ D¤Ŗ  Ŗ Ŗ13”Ŗ wwwŖqwŖqw3wwwŖqwz š’šOōDO@@ōš’’ōDD@@ š/š/’"ć"’ ņ’š’’/#ņ/’"’ąŖźŖ Ŗ Ŗ f` ļ ą fff` Ģ(DLĄČĮ D@@ šš’šš’ššššŠŠ’š’Š@@ĄĄĢĄĢĄĢ šĢĘ ĢĢĢĢĢ ĢĢĢŠ@@š@ł@š 00ćöš@@ŠŠ@ PU@@@EOO000ŖÆ3>3*00030>:33 :3€ØŖ€Øˆ €0š?óš0ś£03030@3C:š@?@š@OO ĢĄ’ĄĄĢĢĄ Ą ĢüĻĢĢ Ąü Ą ĢĢĄĢ Ģ Ģ ĄĢ@0š3@:@£@0£@03@03@033 333303>ć0ć030303>@ž@@3@3@3@3@ ņ%P5PUQ@ņ"BAUAUEQ@@@@DD ņōD"£”j  ŖŖ: :3:33  :Ŗ33:3333303000000™éé™’ ’ ™™™™™™ ™īŸ™ž’ é™™é™ ™ī™é’žīžž’’ĢšĢĢĻĻĢĻĢüšĢĢĻ’Ģ’šĢĢĢüüĻĢüüĢĢ’’šššššš’’’šššš’@D’’š`šff’’šš`šeféī ą®īś ą®īéīąīžŖŖŖś š š’’ ’   ŖŖŖśé™ī ™ ™™™é™™™™™ī’’Ÿé™ž’ ™īŸ™ ™é’ž™ī™™ šĢüüšĢüüšĢĢĻĻĢüĻĻĢšĢĢ’Ģ’ĻĻĢĻĻĢüĢĢĻĢüĢüüĢĢĢ’š’ššš’šš’’’šššš’š’š#0333š0@@03ÓÓ333#00šfVš`UšUUPš’’ef[UUšš’š’@D@ D” D™@’’šJš ’’šDōš š  "҈"‚(ˆDDID ””""‚ˆˆ Ų‚"ˆ""ˆ" "(Ŗš’Ŗś Ŗ ’’š±š»’’ššš»’’š DšD’’š š@”šJš@šš  Æš’’  šš’š’ˆ(‚ ؈ ˆ""  ˆˆŲˆŻ(ˆ("@DDD@DDDDDDD@A A™L ”™ DDDDD@D@@D‚(" ˆ""ˆ"‚€ ˆ‚(ˆ"Ķ ĢČj¢* Ą  O Ą  ’’’ŖŖŖŖŖŖ@D@ D” D™@š±»š±±š±±š’’»šš’š’š šDš@DD@š’’ÆJ@” šš’š’’’šąššš’’šąššą ’’š3#š02’’ššŖš §§ pŹ’’šaša’’ššš’’š€š’’š š(š š’š’š’šąšš’’’ą’ą’ąąšš’š’3s11111P°P°PPUPUPUŠ 03€ˆsŠ3€ˆ3€83swws7w7ww73 Ŗ:£ Ŗ3 3::3 Ŗ ŖˆŖŻŖˆŠš#š0šz§™š’’s 2@#@š@š’š’pŖŖŖwŖŖŖ§ŖŖ§§ŖŖ§wŖz§§w§z§p :§p :: :Ŗ sŖŹĄsŖŖĄs Ź7§ŖŖ§pwŹšaašafšfaš’’ffšš’š’š€š€š"€/€‚/š"’’ ˆŠšˆš’š’3ššš’ššš`’f`f’šaš’š’’šļīļšąī’’šīžšīīffffffffą™ ™ īffffffffī ™ ™ ™ ™ īą ™ ™ īī@Ģ,ĢĢĢ"ĀĢĀ’’šÄĢĄ"Ą,’’šĢLš, š, ’’šš’’ššš™  0jŖŖŖŖ      3 £: ŖŖŖŖŖŖŖ  ’`f`f`fššfš’’fš’fšfšfš’’šššąžšI𐙗™t™šDG’D’”äI™” ™šD@šD’𒐙 īąąą ™ īīīīąą™ffffffff ī™ffffffff™ĢĢĢ’@Ģ"ĢĢĢ"Ģ’’ĢĢšĄĢšĄ"šĄĀš’ÄĢš’’Ģ , , ’šĢLš’š’ššéšžéš’’ ™ž šš’š’’   §z  §@z@@``ffffffff`ffff`šŖŖ ŖŖ  33  £:  £:  33  ŖŖ ŖŖ€ˆ€("ˆ€"š‚€’€šˆ€ˆ€ų’ˆ€ˆ " """ "‚" "ˆ( "‚" ("( ‚ˆ" "ŻŻ  Ńffafffaf@fŻŻ Ż @@ŠŠ@ŽŁ Ž@ąĄĄ±»»±»»±±±±ŖŖŖŖšš’š’’?ŖŖŖś    ’ ’ ó’ ÆŖŖŖ š ’ ’ óŖŖŖŖ’’?š’’šš’’’’’š’’šššĢ ü Ģ      ``00@@€”Ŗ€Ŗ3”ŖŖ@H€AŖA”į˜HĄĢ l”ŹŃĮĢŻĢĢl,ĀL  ĮĶüńĒFĢÄĄĄĄĄĄĄĄaaaaaffffaó’š’0ó03333’? ’ ?    333s š 0 š 0 73333333łŠĮ‘ĀĄŸ Į",€ ( `ff`ffĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢ@€š ခĮ‚ P   ĄĮDL  Į ! DD  Ąfaaa`!&`ffaf"`"`ĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢĢUPUPUUUUPPPUVUUUP  Ŗ Ŗ Ŗ @@ ŖŖ”ŖŖŖ  @@Ŗ ŖŖŖ Ŗ   Ŗ Ŗ Ŗ     30303@@03313330ŠŻ ß Š š`’oą0šąšš’’’š’@šš’ļ’’’’’’š/šˆˆD@DDD»°»»» ŠŠ ŠŻŻŻŠŠŠŻŠ ŻŻ Ż Ż ŻŠŠ " bąb b " " " "öf6f0033333333333330333333s3s33sss030wwwwwwwwwwwww33s ō’š ņ @" O ņšššņ" ˆ€ˆ€(€"(€(€€€ˆˆˆ‰ˆˆDDDDD@@@@@D@DDD@DD »°»PP°»»»»»µ»U µ µ » »» `ff™`ffžfé i–žžn–’Ÿššššš’š@DC@A@Ŗ @DA@@DD303D0D@DC@ww@DDDA@Dww’ff–™ffi™f–f™` ™™™féii™īfifffi`` šššÆOśDš’śś@ÆOōōDAD@’ś ōśśDO@D@’šŖ’ō D@@@@’šÆ’šśÆ?š3š’?3:1?330ŖŖŖŖŖ ŖŖ ŖŖ  Ŗ         ŖŖŖŖŖŖ  0330303033300003333333330000000wwwpwwpwwpwwppwpppppppppwwwwwwpšńš’šń’ń’š’š’’DŖDDD     ŖDDDD  Ŗ ŖD™D™D™™™ ™DDDD™ ™ ™ 36m=ą```fffafęf`ffffffšššžž’ī’’`f  Ŗ Ŗ ŖŖŖŖŖŖ Ŗ Ŗ Ŗ ŖŖŖŖ Ŗ™™™™™™™™™™™™ ™™™™™ ™ ™ ™™ ™™ c30333003303300303333c3fa3fa30afffafa1!``&``fffaf3fa""a`a`šDD@ODDGōDō÷’D’Ļ’’ĻüO ōOO’ļä’ODD’ōšššššššDD$@DDDDB$BDššššššš’š’naff`ff```‘žfįļf ```@DD@DD@”™D DD@@@™™™I™ ”™@”pw7pww7pw73wwsw3gw3wwĄĄ ĄĄĘĢ`Ģ ĢĢĄ ĢĢĢĢĢĄĢĢĄĄ ĄĢ ĄĘ ĢĢĘĢĢlĢĢĢ`aš’’š’’’’’šš’’pppppwžž™I I”I™I™ ™™”™™™™pw73sww3sww7swwwswwswpww0pp3sp3p3pwwwpwpwwĄĢĢĄĢĄĢĢĄĄĢĢĢĢ ĢĄ Ą ĢĄ ĢĢĢĢ ĢĢĄĄĢĢĄĢĢĢĄ Ą ĄĢĢĢĄĢ’’’š’š’ššš’’’’’’’š’ō  ō’ŖšŖššššw÷ Ŗw      ÆOO@’@’š™ žžł@D@M@Mą@Dšīš0šŸ?łJŖ@Ŗ @  @P_@UšPUš Ŗw Ŗw Ŗē 30303w ÷@33õUšPUšššššššŸ’š™  šš’ōšįįš’šįį3> ™€™(˜š"3" ")@‰@(ų#B!"ŖjŖ Ŗ Ŗ f`  ` fff`ffgfv`fg`vf`gf f ’’š’’’’’’’ś’’’ š’   Ŗ Ŗ 3#Ŗ02 §#s 02@z#§@™@PU[PUµPUUPUUPUUUU``ffeffVef`U[UUUUPššššš’’š’’šš@I ™””I™ ™™yD™G@DtDD@šŖŖ? zŖ: Ŗw  :r  #£ 42Ŗ @£Ŗ ¤Ŗ’’w’’Ŗ  § Ŗ§z@@`fa`f`ff`ff`ffff Ŗ§@z@@š’’ššą’’ąšąąžļžļŻŻ  Ż»°»»»»»°A»ÄĢĢLĄ", Ą,, ĄĢĢ Ą", ĄĀ, š’’ÄĢĢLąąššą’’ą’’ą’’ąšąąš D@”DJ ÆDJ@D@”D IDōJ   @    Æ €( € €ˆ"€Š€‚ˆ"f"fbfff`f&f€ˆ€("ˆ€š‚»ń°»ˆ»»»»±»ÆŖśŖŖŖ"2£f"£fb¢fff¢`f&Ŗf¢    § f@fafff`f@f€ˆ€("ˆ€ņ‚f’fafff`fˆf``fffffffffafff`ff``fffffff»a°»»»» »°»ÆŖśŖŖŖ3£»”£°»£»»»” »±”»    § »”@°»»»» »°@»ĄĄ ĢĢĄüĻ ĄüĻ ĢĢĄĄ ™™éž ąļ žžąļ@ž@@ÄĢĢLĄ"" ĄĢ, Ą,Ā ĄĢĢ Ą,Ā š’’ÄĢĢLī`ą™ fą ią™fięīfą`ąąfąī’’’ššš’š. !" !" !" !" !" !" !" !" !" !"012012012012012012012012012012@AB@AB@AB@AB@AB@AB@AB@AB@AB@AB !" !" !" !" !" !" !" !" !" !"012012012012012012012012012012@AB@AB@AB@AB@AB@AB@AB@AB@AB@AB !" !" !" !" !" !" !" !" !" !"012012012012012012012012012012@AB@AB@AB@AB@AB@AB@AB@AB@AB@AB !" !" !" !" !" !" !" !" !" !"012012012012012012012012012012@AB@AB@AB@AB@AB@AB@AB@AB@AB@AB !" !" !" !" !" !" !" !" !" !"012012012012012012012012012012@AB@AB@AB@AB@AB@AB@AB@AB@AB@AB {šššššššššššššššššššššššššššššš           @@@ @ @ @@@+@;@[@k@i@@@@@@@@@@@@@@@@@@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ŠŠ9ŠgŠ ŠŠкГвŠŌŠŠŅŠōŠDŠēŠŠ3ŠQŠäŠŠ ŠäŠāŠ’ŠóŠöŠōŠŠ Šąąąąąąąąąąąą ą ą ą ą ą ą ą ąąąąąąąąąąą``````````````````````````````ąąąąąąąąąąąą ą ą ą ą ą ą ą ąąąąąąąąąąąēęåääāāįįįąąąąąąąąąįįāććäęēēźėPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP````` ` ` ` ` ` ` ` ` ` ` ```````````````aūżEHK M N N OOOOOOOOOOOOOOOOOOOOOOśHGHKMNžNOOOOOOOOOOOOOOOOOOOOO…ų`dgūbfjübfhūadgka c f h j k l l m m n n o ų ` d g g j śaefikłceghiżijllnnnoooomj0g@c0deŠfĄhŠijkklllmmmmmnnnooooooo€ž€<€JHGGŠIĄJŠKL0LPM0NNNNNOOOOOšOOOOOOOO„żæK Hś€ü‡Y`Pppppppppppppppppppppppż€ž žĄżÖžųż ż*ū<żNū_ł`÷pümž\ż;’'ž’õ’Ä’’’€’€’€’€’€’’€’€’€’š0šŠ0@š000šQąRĄSĄU°Z°___________________ š8$6)*+,,---...////////////! ',’žžżžżōW Y[\\=>?????????????ųw÷yVj5jT[4LS]3=S=S-S+TUU6 F 7ųHų8ēIē9ęJÕ:Å;Ä<“<³=³=³>³?³ RHwEPBA B€C DEFGHHIJJKKLLLMMMNNNNO0€öś     ó & ł%ō$ ó # ł óųōęūåõåõäżä÷ÓłÓłÓśŅśŅūĀūĮüĮüĮżĮżĄżĄžĄ’Ą ū°ų°e°d°cĄb°aąa°` `°`0`Ą`@aĄaPbĄc`dĄe`fĄg`hĄi`jĄk`kĄlPmĄn@oĄ ÷*s*s:u:vJwJzZezbj`j`Z`ZaZcJd:e:f*g*hi k |ś}ź}ź~ŚŚŹŹŗŖŒųpPĄbąeee e0t@rPq`r`u`H`L`N`O`O`O`O`O`O`O`O`O`O`O`O`O`O`O` m°o°oĄūŠ’ąnšśžžł ż ų0ü0÷0ü@ö@öPõPõPePžPś@m@ž@ł@ż0n0ż ž ’ L°žĖžūJJ I0H@G`F`FpEpEpD`D`D`DPD@D E EFGšHšIąJąLŠMĄM°N°O ƒšŌ É|}~b` acefghijjjkllmmmmmmmmmmmmmmnnŠ ŃÓÕÖ×ŲŁŚŚŚŪÜÜŻŻŻŻŻŻŻŻŻŻŻŻŻŻŽŽPP PPąąįįāāććääååęęēēččééźźėėģģķķīībšöūżž’’’’’’’’’’’’’’’’’’’’’’’’’±$”};•}‘}D–‘}V—‘g˜‘;”‘&‘‘'‘‘+‘‘@“0‘ ““0’ ‘‘$”};•}‘}D–‘}V—‘g˜‘;”‘&‘‘'‘‘+‘‘} ‘0‘ ““ ‘0‘‘$”};•}‘}D–‘}V—‘g˜‘;”‘&‘‘'‘‘+‘‘G’žG’ž6”ž&”žK“~;‘~N‘~“}+”}‘}D–‘}F–‘W—‘;”‘&‘‘'‘‘+‘‘d”žd’ž6–ž&˜ž;’~K’~K‘~€<,•æ’Ÿ‹˜’Ÿ„˜<€<’Ÿ„˜<d–<‹˜d–<„˜\€<,•æ’Ÿ‹˜’Ÿ„˜<€<’Ÿ„˜<‹˜’摟’æ‘拘’摟’æ’椚<‹˜d–<‹˜‹˜d”^T“^d”^4’^$‘^’^l”>L“>l”><‘><‘>‘>,’0„˜\„–^„˜\d˜^„˜\„–^„˜\d˜^ €Ÿ„˜\d˜>„˜\„–>„˜\ €Ÿō\ €Ÿō\„˜\”™\d˜^”™\„–^”™\„–^ €Ÿ”™\„–^”™\„–~„˜\ €Ÿō\ €Ÿō\T•\‹˜Ÿk–Ÿ‹˜Ÿ˜Ÿ‹˜› €›€› €›€›”€ €€€½€½„˜›€›€›€›€› €{”½€½€ €€€Ž˜{€›ūŸ\«˜>ūŸ\«˜>ūŸ\«˜>ūŸ\«˜> €ŸōŸ\«˜>ōŸ\«˜>ōŸ\«˜>ōŸ\ €Ÿō\„˜\ōŸ\«˜>ōŸ\«˜>ōŸ\«˜> €ŸōŸ\«˜>ōŸ\¬˜>ōŸ\¬˜>ō\ €Ÿō\„˜\ūŸŸ‹˜ŸūŸŸ’ŸŸ÷Ÿ›€›€› €›€› €› €›€{€»€»€» €› €› €›€›•}€} €}€}€€ €€€½€ €€€€}ūŸ{€{†˜›€› €› €› €›€›€ €›€›€›€€›€›€› €{ €{€{ €{ €{€› €{ €{€{D”€€D•€€4“€€E”€4“A’,”K’€4“?$”?K’D”!•’E“’ńŸT•,”ŸD’?K’’‘$’‘D”$’‘$’’”š$’”šńŸńŸ$•€€T’€€4“€€D“€1•D•?Q“$”A’T’$•4“?$”?D’‘4“D”_!•’€’€D”_4•Q“D’?!”!’D”?‘D”_D”‘D”?’”šD”_”šńŸńŸ¤˜^€€–¤˜^¬˜>€–¬˜>€€€4“5€0’$’U €,’U0“’<“50’,“5’ €U€ €5‘€€d”^D“^d”^@“D“^@“€l”>L“>l”>€L“>@“$”};•}‘}D–‘}V—‘g˜‘;”‘&‘‘'‘‘+‘‘€€ € €}€€}€]€}€€]€]$”};•}‘}D–‘}V—‘g˜‘;”‘&‘‘'‘‘'‘‘}€‘}'’}€‘‘}'’]‘‘]'’=€$”};•}‘}D–‘}V—‘g˜‘;”‘&‘‘'‘‘+‘‘@“0‘ ““0’ ‘‘$”};•}‘}D–‘}V—‘g˜‘;”‘&‘‘'‘‘+‘‘} ‘0‘ ““ ‘0‘‘$”}0•‘D–‘}V—‘`˜‘;”‘&‘‘ ‘‘+‘‘`”@‘0””@“0‘ ‘$”};•}‘@–‘}V—‘`˜‘0”‘&‘‘ ‘‘+‘F–‘0 ”‘k”@“@“ 0@”f”@“ €<,•æ’Ÿ‹˜’Ÿ„˜<€<’Ÿ„˜<€<k–?K”€d–<‹˜d–<„˜\€<,•æ’Ÿ‹˜’Ÿ„˜<€<’Ÿ„˜<‹˜’摟’æ‘拘’摟’æ’æ š‹˜d–<‹˜‹˜k–› €›€›€€›”€ €€€½€d–›€€›€›€ €{”€€€€€€€F’^$’^4“^€P’&’^€^G’^P’&’^ €^ ’0’į^+’^)’^6’^'’^D’^€@’D”^K“^K”^V”^€>O’>“}+”}‘}D–‘}F–‘W—‘;”‘&‘‘'‘‘+‘‘d”žd’ž6–ž&˜ž;’~K’~K‘~+”{€{€€;’›‘7’›‘0“‘7”›‘ ‘'’›6‘›“›+‘›‘€€D’›€€&’u'‘U€u€€U&’U‘U $”};•}‘}D–‘}V—‘g˜‘;”‘&‘‘'‘‘'‘‘}€‘}'’}€‘‘}'’]‘‘]'’=€+”U€4ćU€€€6”U‘0“‘•G“•&‘• ’&’u0”6“U “4’U€€u “€u€6’u€U'’u€€U&’U‘U$”};•}‘}D–‘}V—‘g˜‘;”‘&‘‘'‘‘'‘‘}€‘}'’}€‘‘}'’]‘‘]'’=€+”{€{€.’^;’›‘~6’›‘0“‘ž7”›‘ž ‘'’›6“›'’›;“›$’›€€› €›€{€€~€^€~€€^$’^‘^ $”};•}‘}D–‘}V—‘g˜‘;”‘&‘‘'‘‘'‘‘}€‘}'’}€‘‘}'’]‘‘]'’=€F’>$’^0“€€ ’€G’^€ ’€ ’4’^€^ ’ ’7’> ’@’€@’ ’0“@“$’^€^0“€^ ’“}+”}‘}D–‘}F–‘W—‘;”‘&‘‘'‘‘+‘‘d”žd’ž6–ž&˜ž;’~K’~K‘~d–<,•æ’Ÿk–’Ÿd–<€<’ŸT•<4“\€\,•æ’Ÿk–’Ÿd–<<’ŸW•<<“ŸK“<”ŸD” ’0“€>€ ’€G’>€ ’€> ’6’>€ ’&’>;’> ’@’ €>@’ ’6“>@“$’>€€4“>€€$’>€“}+”}‘}D–‘}F–‘W—‘;”‘&‘‘'‘‘+‘‘d”žd’ž6–ž&˜ž;’~K’~K‘~†˜[€[ €[ €[€€€€€[€[€€[€[€› €{ €{€{ €{ €{€› €{ €{€{A”€€D•€€1“€€A”€1“A’,”K’€1“!”K’A”!•’E“’ńŸQ•!”A’A’’‘$’‘A”$’‘$’’”š!’”šńŸńŸ+”^€“€4“^€0”0“ ’‘G“^ ‘0”‘ ’‘~’~€0’€'“>€€6’^€ ‘/“>€ ’6“^$”};•}‘}D–‘}V—‘g˜‘;”‘&‘‘'‘‘'‘‘}€‘}'’}€‘‘}'’]‘‘]'’=€$”;•}‘‘}P—‘`˜‘0”‘&‘‘'‘‘ ‘‘€€ € €}€€€€€ €}€]$”};•}‘’P—‘g˜‘0”‘&‘‘ ‘‘+‘‘€‘ ’€‘‘;”};“ ’0“$’U4“5€0’$’U ,’5,’U0“’<“50’,“5’ €U€ €5‘€€‘~$’}‘}‘}‘}&’}‘}‘})’}‘}'’}‘}€}'’}‘}‘}€$’}‘ €‘} €}€}$’}‘}€}€}&’]‘}'’}€}$”};•}‘}D–‘}V—‘g˜‘;”‘&‘‘'‘‘'‘‘}€‘}'’}€‘‘}'’]‘‘]'’=€‘~$’}‘}‘}‘&’}‘}‘}'’}‘})’}‘}€}'’}‘}‘}€$’}‘} €}‘} €} €})’}‘}€}€}&’]‘]'’]€]$”};•}‘}D–‘}V—‘g˜‘;”‘&‘‘'‘‘'‘‘}€‘}'’}€‘‘}'’]‘‘]'’=€F’=$’]0“€€ ’€G’]€ ’€ ’4’]€] ’ ’4’] ’@’‘@’ ’0“@“$’>€€0“€>€> ’“}+”}‘}D–‘}F–‘W—‘;”‘&‘‘'‘‘+‘‘d”žd’ž6–ž&˜ž;’~K’~K‘~‘~$’}‘}€}€&’}‘}€}€'’}‘}€}€&’}‘}€}€$’}‘} €}€+’}‘}€}€$’}‘}€€€$”};•}‘}D–‘}V—‘g˜‘;”‘&‘‘'‘‘'‘‘}€‘}'’}€‘‘}'’]‘‘]'’=€6“Y€‘&’Y6“Y>“9F”Y  0“@”€‘@”€@”€0“@”@”@”€€@”0“@” ’0€~‘&“~4“~%“~€^ “‘1“1’€€€€€€€€€€€’@@ąĄćĄC(ĄC,ä(@ä@D@DHĄCHDH€` €`,€(€3@@@4ąąx@x@4ąē4ą@ĄBxĄāxGx@4ą4€@†€¢m@†…@†…€¢§€B€BU@aU@aUĄ\ĄB]@fU@aU@  Œ Ž Ž j€€‚€B€Bu€B…ĄB…ĄBUGUG]\ ˜pš@–Ą?ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»UUUU»»»»»»»»»»»»UUUU»»»»»»»»»»»»UUUU»»»»»»»»»»»»UUUU»»»»»»»»»»»»UUUU»»»»»»»»»»»»UUUU»»»»»»»»»»»»UUUU»»»»»»»»»»»»UUUU»»»»į ŖŖŖś š š’’ ’   ŖŖŖśå-- title: Sleepless Cards v1.1 - CONTENT EXPANSION -- author: Sleepless Creator -- desc: Roguelite card game where each run takes 20-40 mins. -- site: sleeplesscards.com -- version: 1.1 -- script: lua -- saveid: ReleaseSleeplessCards function BOOT() InitVars() GUIScenarioStepCreator:Init() GUIScenarioCreator:Init() GUIScenarioQueueSystem:Init() InitBaseGUI() GUICreator:CreateMainMenuScreens() MusicHelper:TurnMusicOn() init_particles() end function TIC() local deltaTime=glFrameTimePerFrame Logger:CalculateFPS(deltaTime) MusicHelper:Update(deltaTime) if gameInitialized then UpdateGame(glFrameTimePerFrame) else UpdateBase(glFrameTimePerFrame) end update_psystems() Draw() end --draw GUI function OVR() DrawBeforeGUI() ticuare.draw() DrawAfterGUI() draw_psystems() if glDebugMode then Logger:Render() end end function InitSeed(seed,reInit) glGameSeed=seed math.randomseed(glGameSeed) math.random() if reInit then InitThingsRequiringGameSeed() end Logger:Debug("GAME SEED:"..seed) end function InitVars(seed) Logger:Init() glDebugMode=false if seed then InitSeed(seed) else if glDebugMode then math.randomseed(0) else InitSeed(math.random(999999)) end end glVersionBlurbTextArray={"v1.1: content expansion released!","visit discord or reddit to read full changelog","","v1.031: hotfix","v1.03: bugfixes","v1.02: bugfixes & improvements","v1.01: fixes exception on leader, bug in tag system","v1.0: RELEASE VERSION!"} glCreditsBlurbTextArray={"CODE - Sleepless Creator","PARTICLE LIBRARY - visa", "GUI LIBRARY - crutiatix","GRAPHICS - Oryx Design Lab, Krishna Palacio,","Sleepless Creator","SOUNDS - petet","MUSIC - petet, Sleepless Creator","SPECIAL THANKS - Pajka, Iga, Mroku,","Dennis Smuda, Krishna Palacio, petet,", "Martyna, Mariusz, Kasia, Zuzia, cokeandcode", "", "Sleepless Creator - sleeplesscards.com"," reddit.com/r/sleeplesscards"," sleeplesscreator.com","petet - @retropetet"} glFrameTimePerFrame=1.0/60.0 glInitialized=true glScreenPixelWidth=240 glScreenPixelHeight=136 glScreenTileWidth=pix2Tile(glScreenPixelWidth) glScreenTileHeight=pix2Tile(glScreenPixelHeight) glScreenPixelHalfWidth=glScreenPixelWidth/2 glScreenPixelHalfHeight=glScreenPixelHeight/2 glTilemapWidth=240 glTilemapHeight=128 glTilemapPixelWidth=tile2Pix(glTilemapWidth) glTilemapPixelHeight=tile2Pix(glTilemapHeight) glTransparentColor=0 glColorBlack=0 glDarkViolet=1 glDarkBlue=2 glTitleColor=15 glEnemyTitleBackColor=1 glTextBackColor=0 glStatsBackColor=0 glSFXUnitAttacks=3 glSFXUnitDoesAction=5 glSFXTagHealedProc=8 glSFXGUIControlAppeared=10 glSFXUIButtonClickedNotActive=17 glSFXUIButtonClicked=16 glSFXConfirmGUIData={ name="confirm GUI", id=16, noteMin=60, noteMax=60, noteDef=60 } glSFXCancelGUIData={ name="cancel GUI", id=17, noteMin=50, noteMax=50, noteDef=50 } glSFXStartOfNewTurn=18 glSFXNewTurnData={ name="new turn", id=18, noteMin=48, noteMax=48, noteDef=48 } glSFXEndOfTurn=19 glSFXEndTurnData={ name="end turn", id=19, noteMin=36, noteMax=36, noteDef=36 } glSFXGainMana=20 glSFXGainManaData={ name="gain mana", id=20, noteMin=60, noteMax=90, noteDef=60, notesList={60,67,72,76,79,82,84,86,88,90} } glSFXSpendMana=21 glSFXSpendManaData={ name="spend mana", id=21, noteMin=72, noteMax=84, notesList={72,73,76,77,79,80,83,84,85,88} } glSFXCardDrawn=23 glSFXDrawCardData={ name="draw card", id=23, noteMin=45, noteMax=75, noteDef=50, } glSFXHealthLoss=24 glSFXHPDamageData={ name="HP attack", id=24, noteMin=30, noteMax=70, noteDef=50, } glSFXArmorLoss=25 glSFXArmorDamageData={ name="armor attack", id=25, noteMin=35, noteMax=45, noteDef=40, } glSFXUnitAttacks=3 glSFXRangedAttackData={ name="ranged attack", id=26, noteMin=35, noteMax=45, noteDef=40, } glSFXUnitDestroyed=27 glSFXUnitDeathData={ name="death", id=27, noteMin=30, noteMax=70, noteDef=50, } glSFXSpellCasted=28 glSFXCastBuffSpellData={ name="buff spell", id=28, noteMin=48, noteMax=72, noteDef=60, } glSFXCastDebuffSpellData={ name="debuff spell", id=29, noteMin=48, noteMax=72, noteDef=50, } glSFXCastDamageSpellData={ name="damage spell", id=30, noteMin=25, noteMax=75, noteDef=40, } glSFXCastSummonSpellData={ name="summon spell", id=31, noteMin=25, noteMax=75, noteDef=40, } glSFXUnitSummoned=31 glSFXSummonBeastUnitData={ name="summon beast 1", id=31, noteMin=30, noteMax=70, noteDef=50, } glSFXSummonHumanUnitData={ name="summon human 1", id=32, noteMin=30, noteMax=50, noteDef=45, } glSFXUnused1Data={ name="summon human 2", id=33, noteMin=30, noteMax=50, noteDef=45, } glSFXUnused2Data={ name="summon undead 1", id=34, noteMin=30, noteMax=70, noteDef=45, } glSFXSummonUndeadUnitData={ name="summon undead 2", id=35, noteMin=30, noteMax=70, noteDef=50, } glMusicGameLost=59 glMusicGameWon=60 glFrameFirstFrame=true glFrameEveryOther=false glFrame10thFrame=false glFrame15thFrame=false glFrame20thFrame=false glFrame25thFrame=false glFrame30thFrame=false glFrame60FramesCounter=0 glFramesCounter=0 --second/framesPerSecond glFrameTimePerFrame=1.0/60.0 glSecondsElapsed=0 glPulseStatusForEvery10thFrame=false glPulseStatusForEvery15thFrame=false glPulseStatusForEvery30thFrame=false glScreenShakeVal=0 glMouse={ x=0, y=0, lastX=0, lastY=0, screenTileX=0, screenTileY=0, worldX=0, worldY=0, worldTileX=0, worldTileY=0, realX=0, realY=0, realLastX=0, realLastY=0, } glButtons= { up=false, down=false, left=false, right=false, a=false, b=false, x=false, y=false, } InitCSVData() GUIHelper.playerHandCards={} GUIHelper.playerBattlefieldCards={} GUIHelper.enemyBattlefieldCards={} GUIHelper.controlHoveredTime=0 AsyncQueueLogicHelper.queue={} AsyncQueueDrawHelper.queue={} glMsgType={ LOGGER="LOGGER", NONE=nil, INIT_BASE="INITB", INIT_GAME="INITG", GUI="GUI", GAME_LOGIC="GLOGIC", TUTORIAL="TUTORIAL", AI="AI", EVENT="EVENT", TAG="TAG", DEBUG_HELPER="DEBUG", MUSIC="MUSIC", SFX="SFX", SCENARIO_GUI="SCEN_GUI", STEP_GUI_CREATOR="STEP_GUI_CREATOR", SCENARIO_GUI_CREATOR="SCEN_GUI_CREATOR" } glGameTarget={ ANY_LEADER=100, OWN_LEADER=110, ENEMY_LEADER=120, ANY_UNIT=200, OWN_UNIT=210, ENEMY_UNIT=220, OWN_CARD_IN_HAND=300, ENEMY_CARD_IN_HAND=400, } glGameStates={ START_TURN=0, TURN_IN_PROGRESS=1, UNIT_SUMMON=20, UNIT_ATTACK_LEADER=30, UNIT_ATTACK_UNIT=40, CASTING_SPELL=50, } glEventTypes={ TUTORIAL_INIT="TUTORIAL_INIT", MATCH_STARTED="MATCH_STARTED", DAMAGE_DEALT="DAMAGE_DEALT", UNIT_SUMMONED="UNIT_SUMMONED", UNIT_WAS_ATTACKED="UNIT_WAS_ATTACKED", UNIT_DIED="UNIT_DIED", CARD_DRAWN="CARD_DRAWN", SPELL_CASTED_ON="SPELL_CASTED_ON", TURN_ENDED="TURN_ENDED", DECK_CREATED="DECK_CREATED", LEADER_CREATED="LEADER_CREATED", } glUnitDeathTypes={ TAG="TAG", ATTACKED_BY_UNIT="ATTACKED_BY_UNIT", CARD_DRAW="CARD_DRAW", CASTED_SPELL="CASTED_SPELL", } EventHelper:Init() DebugHelper:Init() glTooltipsStrings={ buttonEndTurn={{text="This will end your current turn",c=10}, {text="and will start enemy turn",c=10},}, buttonOptions={{text="Options menu which contains game settings",c=10}, {text="that can be changed mid-game",c=10},}, panelManaCount={{text="Available MANA / Current max MANA",c=15},{text="MANA is used to play cards from hand",c=10}, {text="Every turn you regen. all your MANA",c=10}, {text="and get one more max up to 9 max",c=10}, {text="Faded crystals represent spent MANA",c=10}, {text="while bright ones represent available to use",c=10},}, panelCardCount={{text="CARDS in hand / CARDS left in the deck",c=15}, {text="Player draw one card per their own turn",c=10}, {text="and there can be only 7 cards in hand at once",c=10}, {text="If deck is empty, owner leader will be damaged",c=10}, {text="with DMG to HP increasing with each empty draw",c=10},}, panelCreateLeaderStats="Use this to determine starting values with which your leader unit will start each fight.", panelCreateLeaderTags="Use this to give your leader unit TAGS that change rules of battle of how unit behaves with which your leader unit will start each fight.", panelCreateLeaderAvatar="Use this to select avatar that will represent your leader unit look each fight.", } glLeaderArtifacts={ DEFAULT={id="DEFAULT",name="NULL",enabled=false, desc={{c=15,str="This is unknown REWARD and isn't supported by the game at this moment"}}}, DOUBLE_HP={id="DOUBLE_HP",name="DOUBLE HEALTH",enabled=true, desc={{c=15,str="Double your leader current HP stat"},{c=15,str="(or add 5 if current HP is <10)"}}}, DOUBLE_ARMOR={id="DOUBLE_ARMOR",name="DOUBLE ARMOR",enabled=true, desc={{c=15,str="Double your leader current ARMOR stat"},{c=15,str="(or add 5 if current ARMOR is <10)"}}}, DOUBLE_ATK={id="DOUBLE_ATK",name="DOUBLE ATTACK",enabled=true, desc={{c=15,str="Double your leader current ATK stat"},{c=15,str="(or set to 1 if current ATK is <1)"}}}, LIFE_UP={id="LIFE_UP",name="ONE MORE CHANCE",enabled=true,unique=false,desc={{c=15,str="Your leader can die one more time this run."}}}, REVIVE_ANKH={id="REVIVE_ANKH",name="REVIVE ANKH",enabled=true,unique=true,desc={{c=15,str="Your leader get's healed to full once instead of being killed. Then this artifact gets destroyed."}}}, SELECT_STARTING_CARDS={id="SELECT_STARTING_CARDS",name="REDRAW CARDS",enabled=true,unique=true, desc={{c=15,str="You can redraw your starting cards as much as you want"}}}, DRAW_2_MORE_CARDS={id="DRAW_2_MORE_CARDS",name="DRAW MORE CARDS",enabled=true,unique=true, desc={{c=15,str="You draw additional 2 cards when starting the fight"}}}, MORE_MANA={id="MORE_MANA",name="MORE MANA",enabled=true,unique=true, desc={{c=15,str="You start with 2 mana and max out at 10 max."}}}, ADDITIONAL_CARD_BUCKETS={id="ADDITIONAL_CARD_BUCKETS",name="MORE CARD BUCKETS",enabled=true,unique=true, desc={{c=15,str="You have two card buckets screen every fight instead of one"}}}, TWICE_THE_ARTIFACTS={id="TWICE_THE_ARTIFACTS",name="TWICE THE ARTIFACTS",enabled=true,unique=true,lvl=2,desc={{c=15,str="From next artifact choosing,"},{c=15,str="you get to choose two artifacts instead of one."}}}, TWO_MANA_PER_TURN={id="TWO_MANA_PER_TURN",name="2 MANA PER TURN",enabled=true,unique=true, desc={{c=15,str="Every turn you get 2 mana points more instead of 1,"},{c=15,str="starting from your second turn."}}}, LEGENDARY_CARD={id="LEGENDARY_CARD",name="LEGENDARY CARD",enabled=true, desc={{c=15,str="Choose one legendary unit from provided selection"},{c=15,str="and add it to your deck"}}}, ENEMY_CARDS_VISIBLE={id="ENEMY_CARDS_VISIBLE",name="ENEMY CARDS VISIBLE",enabled=true,unique=true,desc={{c=15,str="See what cards are drawn by the enemy."}}}, SUMMON_WEAK_ZOMBIE={id="SUMMON_WEAK_ZOMBIE",name="WEAK ZOMBIE ON DEATH",enabled=true,desc={{c=15,str="Have summoned 1/1 zombie for your side each time enemy unit dies."}}}, } glCardBuckets={ ANIMAL={name="ANIMAL",allCards={},buckets={{"A002","A023","A024"}}}, HUMAN={name="HUMAN",allCards={},buckets={{"H004","H011","H017"}}}, UNDEAD={name="UNDEAD",allCards={},buckets={{"U015","U010","U017"}}}, DASH={name="DASH",}, VENOM={name="VENOM",}, POISON={name="POISON",}, NIMBLE={name="NIMBLE",}, DISTRACT={name="DISTRACT",}, STEAL={name="STEAL",}, PIERCE={name="PIERCE",}, CLEAVE={name="CLEAVE",}, DRAIN={name="DRAIN",}, DISARM={name="DISARM",}, FEARED={name="FEARED",}, HEALER={name="HEALER",}, DRAW={name="DRAW",}, INSPIRES={name="INSPIRES",}, SUMMON={name="SUMMON",}, RANGED={name="RANGED",}, SPELLS={name="SPELLS",}, LEGENDARY={name="LEGENDARY",}, RARE={name="RARE",}, VERY_SOMETHING={name="VERY_SOMETHING"}, SMALL={name="SMALL"}, MEDIUM={name="MEDIUM"}, LARGE={name="LARGE"}, } local onBuffTagCreationFunc=function(unitTag,cardObj,simulateOnly) local typeName=unitTag.data.split[2] if unitTag and not simulateOnly then if typeName=="ARMOR" then unitTag.spr=505 elseif typeName=="ATK" then unitTag.spr=506 elseif typeName=="MANA" then unitTag.spr=499 elseif typeName=="HP" then unitTag.spr=504 elseif typeName=="SPELLPWR" then unitTag.spr=492 end end end local onCutTagCreationFunc=function(unitTag) local typeName=unitTag.data.split[2] if unitTag and not simulateOnly then if typeName=="ARMOR" then unitTag.spr=500 elseif typeName=="ATK" then unitTag.spr=501 elseif typeName=="MANA" then unitTag.spr=502 elseif typeName=="HP" then unitTag.spr=503 elseif typeName=="SPELLPWR" then unitTag.spr=261 end end end local triggersWhenAttackingDesc={c=10,str="Triggers when attacking target"} glUnitTags={ DEFAULT={spr=511,data={},desc={{c=10,str="This is unknown TAG and isn't supported by the game at this moment"}},genDesc=function(self,cardObj) return self.desc end, genName=function(self,cardObj) return {self.name} end,}, DASH={spr=480,data={},costValue=1, desc={{c=15,str="Allows this unit to attack"},{c=15,str="on summoning turn"}},genDesc=function(self,cardObj) return self.desc end, funcAfterBeingSummoned=function(self,cardObj,simulateOnly) cardObj.stats.attacksAvail:setToMax() end, genName=function(self,cardObj) return {self.name} end, }, VENOM={spr=481,data={},costValue=5,desc={triggersWhenAttackingDesc,{c=9,str="with no armor"},{c=15,str="the target gets killed if HP<=5,"},{c=15,str="otherwise cut target unit HP in half"}}, funcBeforeAttacking=function(self,cardObj,enemyCardObj,cardGUI,enemyCardGUI,simulateOnly) if (cardObj:GetTagByName(glUnitTags.PIERCE.name) or enemyCardObj.stats.armor.cur<=0) and enemyCardObj.stats.hp:aboveMin() then if not simulateOnly and enemyCardGUI then ParticleHelper:CreateWoundedFX(enemyCardGUI:getCenterX(),enemyCardGUI:getCenterY(),99,0,(string.sub(enemyCardObj.id,1,1)=="U" and 5 or 6)) end local v=enemyCardObj.stats.hp.cur if v<=5 then EventHelper:ExecuteEvent(glEventTypes.UNIT_DIED,self,simulateOnly,{cardObj=cardObj,initingObj=enemyCardObj,typeOfDeath=glUnitDeathTypes.ATTACKED_BY_UNIT}) GameHelper:DestroyUnit(enemyCardObj,enemyCardGUI,0,simulateOnly) else v=math.floor(v/2) enemyCardObj.stats.hp:div(2) end GUIHelper:DrawChangeIndicator(enemyCardGUI,"HP",-v,delayForFX) end end, genName=function(self,cardObj) return {self.name} end, genDesc=function(self,cardObj) return self.desc end,}, POISON={spr=483,data={},costValue=3,desc={triggersWhenAttackingDesc,{c=9,str="with no armor"},{c=15,str="the target unit gets the TAG POISONED"},{c=7,str="(-1 HP on end of their turn)"}}, funcBeforeAttacking=function(self,cardObj,enemyCardObj,cardGUI,enemyCardGUI,simulateOnly) if (cardObj:GetTagByName(glUnitTags.PIERCE.name) or enemyCardObj.stats.armor.cur<=0) then enemyCardObj:InsertTag(deepcopy(glUnitTags.POISONED),simulateOnly) end end, genName=function(self,cardObj) return {self.name} end, genDesc=function(self,cardObj) return self.desc end, }, NIMBLE={spr=482,data={},costValue=3,desc={{c=15,str="Allows to attack one more time per turn"}}, genDesc=function(self,cardObj) return self.desc end, genName=function(self,cardObj) return {self.name} end, funcOnCreatingThisTagOnUnit=function(self,cardObj,simulateOnly) cardObj.stats.attacksAvail.max=cardObj.stats.attacksAvail.max+1 cardObj.stats.attacksAvail:incr() end, funcAfterBeingSummoned=function(self,cardObj,simulateOnly) --hacks for special cases if cardObj.isLeaderCard then cardObj.stats.attacksAvail.max=cardObj.stats.attacksAvail.max+1 end if cardObj:GetTagByName(glUnitTags.DASH.name) then cardObj.stats.attacksAvail:setToMax() else cardObj.stats.attacksAvail:setToMin() end end}, POISONED={spr=484,data={},costValue=-3,desc={{c=15,str="Unit gets 1 HP DMG every time their turn ends"}}, genDesc=function(self,cardObj) return self.desc end, funcOnEveryTurnEnd=function(self,cardObj,cardGUI,simulateOnly) if (cardObj.isPlayerCard and GameHelper.isPlayerTurn) or (not cardObj.isPlayerCard and not GameHelper.isPlayerTurn) then cardObj.stats.hp:decr() GUIHelper:DrawChangeIndicator(enemyCardGUI,"HP",-1,delayForFX) if not simulateOnly then GUIHelper.ShakeFrameControl(cardGUI,4,0.2,0) end if not cardObj.stats.hp:aboveMin() then EventHelper:ExecuteEvent(glEventTypes.UNIT_DIED,self,simulateOnly,{cardObj=cardObj,initingObj=nil,typeOfDeath=glUnitDeathTypes.TAG}) GameHelper:DestroyUnit(cardObj,cardGUI,0) end end end, genName=function(self,cardObj) return {self.name} end, }, DISTRACT={spr=485,data={},costValue=-1,desc={{c=15,str="Forces enemy units to attack"},{c=15,str="unit(s) with this TAG first"}}, genDesc=function(self,cardObj) return self.desc end, genName=function(self,cardObj) return {self.name} end,}, SLOW={spr=497,data={turnPassed=4},costValue=-2,desc={{c=15,str="This unit can only attack every other turn"}}, genDesc=function(self,cardObj) return self.desc end, funcAfterInit=function(self,cardObj,simulateOnly) self.data.turnPassed=4 end, funcOnCheckingIfUnitCanAttack=function(self,cardObj,simulateOnly) return self.data.turnPassed>3 end, funcOnEveryTurnEnd=function(self,cardObj,cardGUI,simulateOnly) if self.data.attackedThisTurn then self.data.turnPassed=0 self.data.attackedThisTurn=nil end self.data.turnPassed=self.data.turnPassed+1 if not self:funcOnCheckingIfUnitCanAttack(cardObj,simulateOnly) then cardObj.stats.attacksAvail:setToMin() end end, funcAfterAttacking=function(self,cardObj,enemyCardObj,cardGUI,enemyCardGUI,simulateOnly) self.data.attackedThisTurn=true end, genName=function(self,cardObj) return {self.name} end, }, STEAL={spr=486,data={},costValue=2,desc={triggersWhenAttackingDesc,{c=15,str="Steals half of target ATK value"},{c=15,str="and adds it to the owner unit ATK"}}, genDesc=function(self,cardObj) return self.desc end, genName=function(self,cardObj) return {self.name} end, funcAfterAttacking=function(self,cardObj,enemyCardObj,cardGUI,enemyCardGUI,simulateOnly) local atk=enemyCardObj.stats.attack.cur local half=math.floor(atk/2) if half>0 then GameHelper:ApplyCutTo(enemyCardObj,enemyCardObj.cardGUI,"atk",half,0.25,simulateOnly) local t=deepcopy(glUnitTags.CUT) t.data.spellPWR=half t.data.split={"CUT","ATK"} if t.funcOnCreatingThisTagOnUnit then t:funcOnCreatingThisTagOnUnit(enemyCardObj,simulateOnly) end enemyCardObj:InsertTag(t,simulateOnly) self.data.enemyCutTag=t self.data.unitObjStolenFrom=enemyCardObj GameHelper:ApplyBuffTo(cardObj,cardObj.cardGUI,"atk",half,0.25,simulateOnly) t=deepcopy(glUnitTags.BUFF) t.data.spellPWR=half t.data.split={"BUFF","ATK"} if t.funcOnCreatingThisTagOnUnit then t:funcOnCreatingThisTagOnUnit(cardObj,simulateOnly) end cardObj:InsertTag(t,simulateOnly) end end, }, DISARM={spr=490,data={},costValue=2,desc={triggersWhenAttackingDesc,{c=15,str="Sets target unit ATK value to 1"}}, genDesc=function(self,cardObj) return self.desc end, funcAfterAttacking=function(self,cardObj,enemyCardObj,cardGUI,enemyCardGUI,simulateOnly) --TODO: change to afterdealingdamage? local val=enemyCardObj.stats.attack.cur-1 GameHelper:ApplyCutTo(enemyCardObj,enemyCardObj.cardGUI,"atk",val,0.25,simulateOnly) if val>0 then t=deepcopy(glUnitTags.CUT) t.data.split={"CUT","ATK"} t.data.spellPWR=val if t.funcOnCreatingThisTagOnUnit then t:funcOnCreatingThisTagOnUnit(enemyCardObj,simulateOnly) end enemyCardObj:InsertTag(t,simulateOnly) end end, genName=function(self,cardObj) return {self.name} end, }, PIERCE={spr=487,data={},costValue=2,highPriority=true,desc={triggersWhenAttackingDesc,{c=15,str="Dealt damage ignores target ARMOR"}}, genDesc=function(self,cardObj) return self.desc end, funcBeforeAttacking=function(self,cardObj,enemyCardObj,cardGUI,enemyCardGUI,simulateOnly) local armor=enemyCardObj.stats.armor.cur self.data.armor=armor enemyCardObj.stats.armor:setToMin() end, funcAfterAttacking=function(self,cardObj,enemyCardObj,cardGUI,enemyCardGUI,simulateOnly) local a=enemyCardObj.stats.armor.cur enemyCardObj.stats.armor.cur=self.data.armor end, genName=function(self,cardObj) return {self.name} end,}, CLEAVE={spr=488,data={},costValue=3,desc={triggersWhenAttackingDesc,{c=15,str="Damages adjacent units as well"}}, genDesc=function(self,cardObj) return self.desc end, funcAfterAttacking=function(self,cardObj,enemyCardObj,cardGUI,enemyCardGUI,simulateOnly) if self.data.alreadyUsedCleave then return end self.data.alreadyUsedCleave=true local n=0 if cardGUI then foreach(GameHelper:GetAdjacentUnitsToProvided((enemyCardObj.isPlayerCard and GameHelper.playerBattlefieldCards or GameHelper.enemyBattlefieldCards),enemyCardObj), function(battleCardObj) GameHelper:ApplyDamageTo(battleCardObj,battleCardObj.cardGUI,cardGUI,cardObj.stats.attack.cur,0.4+0.05*(2-GameHelper.animationSpeed)+n,simulateOnly) n=n+0.1 end) end self.data.alreadyUsedCleave=false end, genName=function(self,cardObj) return {self.name} end,}, DRAIN={spr=489,data={},costValue=3,desc={triggersWhenAttackingDesc,{c=9,str="with no armor"},{c=15,str="Dealt damage restores HP equal to ATK value"}}, genDesc=function(self,cardObj) return self.desc end, genName=function(self,cardObj) return {self.name} end, funcAfterAttacking=function(self,cardObj,enemyCardObj,cardGUI,enemyCardGUI,simulateOnly) if (cardObj:GetTagByName(glUnitTags.PIERCE.name) or enemyCardObj.stats.armor.cur<=0) then GameHelper:ApplyHealTo(cardObj,cardObj.cardGUI,cardObj.stats.attack.cur,0.2,simulateOnly) end end, }, FEARED={spr=491,data={},costValue=2,desc={{c=15,str="Can be attacked only by a unit"},{c=15,str="with same or higher ATK value"}}, genName=function(self,cardObj) return {self.name} end, genDesc=function(self,cardObj) return self.desc end, funcCheckIfCanBeAttackedBy=function(self,cardObj,enemyCardObj,cardGUI,enemyCardGUI,simulateOnly) return enemyCardObj.stats.attack.cur>=cardObj.stats.attack.cur end}, HEALER={spr=507,data={},costValue=3,desc={{c=15,str="Heal 1 HP for owner and adjacent units"},{c=15,str="at the end of *THEIR* turn"}},genDesc=function(self,cardObj) return self.desc end, funcOnUnitTurnEnd=function(self,cardObj,cardGUI,simulateOnly) if not simulateOnly then GUIHelper.ShakeFrameControl(cardGUI,4,0.2,0) AsyncQueueLogicHelper:AddToQueue(function(data) SfxHelper:PlaySFX(glSFXTagHealedProc,nil,40) end,{},delayForFX) end GameHelper:ApplyHealTo(cardObj,cardGUI,1,0,simulateOnly) local n=0 foreach(GameHelper:GetAdjacentUnitsToProvided((cardObj.isPlayerCard and GameHelper.playerBattlefieldCards or GameHelper.enemyBattlefieldCards),cardObj), function(battleCardObj) GameHelper:ApplyHealTo(battleCardObj,battleCardObj.cardGUI,1,n,simulateOnly) n=n+0.1 end) end, genName=function(self,cardObj) return {self.name} end,}, DRAW={spr=493,data={},costValue=1,desc={{c=15,str="Draw 1 card after summoning this unit"}}, genDesc=function(self,cardObj) return self.desc end, funcAfterBeingSummoned=function(self,cardObj,simulateOnly) AsyncQueueLogicHelper:AddToQueue(function(data) if not simulateOnly then GameHelper:ExecuteDrawCard(data.cardObj.isPlayerCard) end end,{cardObj=cardObj},0.5) end, genName=function(self,cardObj) return {self.name} end,}, INSPIRED={spr=506,data={},desc={{c=15,str="ATK is increased by 1"}}, genDesc=function(self,cardObj) return self.desc end, genName=function(self,cardObj) return {self.name} end, }, INSPIRES={spr=494,data={attackUpped=false},costValue=4,desc={{c=15,str="Adds INSPIRED TAG to adjacent units"},{c=15,str="as long as this unit is alive"},{c=9,str="INSPIRED"},{c=9,str="ATK is increased by 1"}}, genDesc=function(self,cardObj) return self.desc end, genName=function(self,cardObj) return {self.name} end, funcOnOtherUnitBeingSummoned=function(self,cardObj,cardGUI,otherCardObj,othercardGUI,simulateOnly) if simulateOnly then return end foreach(GameHelper:GetAdjacentUnitsToProvided((cardObj.isPlayerCard and GameHelper.playerBattlefieldCards or GameHelper.enemyBattlefieldCards),cardObj), function(battleCardObj) if battleCardObj==otherCardObj then if not battleCardObj:GetTagByName("INSPIRED") then GameHelper:ApplyBuffTo(otherCardObj,othercardGUI,"INSPIRED",1,0.25,simulateOnly) local unitTag=deepcopy(glUnitTags["INSPIRED"]) otherCardObj:InsertTag(unitTag,simulateOnly) end end end) end, funcAfterBeingSummoned=function(self,cardObj,simulateOnly) if simulateOnly then return end foreach(GameHelper:GetAdjacentUnitsToProvided((cardObj.isPlayerCard and GameHelper.playerBattlefieldCards or GameHelper.enemyBattlefieldCards),cardObj), function(battleCardObj) if battleCardObj~=cardObj then if not battleCardObj:GetTagByName("INSPIRED") then GameHelper:ApplyBuffTo(battleCardObj,battleCardObj.cardGUI,"INSPIRED",1,0.25,simulateOnly) local unitTag=deepcopy(glUnitTags["INSPIRED"]) battleCardObj:InsertTag(unitTag,simulateOnly) end end end) end, funcOnUnitDestroy=function(self,cardObj,cardGUI,simulateOnly) if simulateOnly then return end foreach(GameHelper:GetAdjacentUnitsToProvided((cardObj.isPlayerCard and GameHelper.playerBattlefieldCards or GameHelper.enemyBattlefieldCards),cardObj), function(battleCardObj) if battleCardObj~=cardObj then local tag=battleCardObj:GetTagByName("INSPIRED") if tag then GameHelper:ApplyCutTo(battleCardObj,battleCardObj.cardGUI,"INSPIRED",1,0.25,simulateOnly) battleCardObj:RemoveTagByObj(tag,simulateOnly) end end end) end, funcOnCreatingThisTagOnUnit=function(self,cardObj,simulateOnly) self:funcAfterBeingSummoned(cardObj,simulateOnly) end, funcOnRemovingThisTag=function(self,cardObj,simulateOnly) self:funcOnUnitDestroy(cardObj,cardObj.cardGUI,simulateOnly) end, }, SUMMON={spr=495,data={split={}},desc={{c=15,str="Summon new unit with ID provided"},{c=15,str="on first empty space available"}}, genDesc=function(self,cardObj) return self.desc end, funcAfterBeingSummoned=function(self,cardObj,simulateOnly) AsyncQueueLogicHelper:AddToQueue(function(data) local cardID=data.split[2] if cardID and GameHelper.allCards[cardID] then local isPlayer=data.cardObj.isPlayerCard local n=0 for i=1,6 do local bf=(isPlayer and GameHelper.playerBattlefieldCards or GameHelper.enemyBattlefieldCards) if not bf[i] then n=i break end end if n>0 then if not simulateOnly then local unit=GameHelper:SummonUnitOntoBattlefield(GameHelper.allCards[cardID]:DeepCopy(),n,isPlayer) if unit then local unitTag=deepcopy(glUnitTags["SUMMONED"]) unit:InsertTag(unitTag,simulateOnly) end end end end end,{split=self.data.split,cardObj=cardObj},0.5) end, genName=function(self,cardObj) return {self.name,(self.data.split[2] or "")} end, }, SUMMONED={spr=142,data={split={}},desc={{c=15,str="If this tag gets removed"},{c=15,str="this unit will be destroyed"}}, genDesc=function(self,cardObj) return self.desc end, funcOnRemovingThisTag=function(self,cardObj,simulateOnly) GameHelper:ApplyDamageTo(cardObj,cardObj.cardGUI,cardObj.cardGUI,cardObj.stats.hp.cur+cardObj.stats.armor.cur,0.25,simulateOnly) end, genName=function(self,cardObj) return {self.name} end, }, RANGED={spr=496,data={},costValue=3,desc={{c=10,str="Attacking target unit procs this:"},{c=15,str="target unit doesn't attack back"}}, genDesc=function(self,cardObj) return self.desc end, genName=function(self,cardObj) return {self.name} end, }, SPELLPWR={spr=267,data={split={}},desc={{c=15,str="SPELLPWR is "},{c=9,str="and it affects *EVERY* card"},{c=9,str="that uses SPELLPWR"},}, genName=function(self,cardObj) return {self.name,(self.data.split[2] or ""),(self.data.split[2]=="UP" and "+" or "-")..self.data.spellPWR} end, genDesc=function(self,cardObj) return {{c=15,str=self.desc[1].str..(self.data.split[2]=="UP" and "increased" or "decreased").." by "..(self.data.spellPWR or 0)},self.desc[2],self.desc[3],} end, funcOnRemovingThisTag=function(self,cardObj,simulateOnly) if self.data.split[2]=="DOWN" then GameHelper:ApplyBuffTo(cardObj,cardObj.cardGUI,"SPELLPWR",self.data.spellPWR,0.25,simulateOnly) else GameHelper:ApplyCutTo(cardObj,cardObj.cardGUI,"SPELLPWR",self.data.spellPWR,0.25,simulateOnly) end end, funcAfterBeingSummoned=function(self,cardObj,simulateOnly) if self.data.split[2]=="DOWN" then GameHelper:ApplyCutTo(cardObj,cardObj.cardGUI,"SPELLPWR",self.data.spellPWR,0.25,simulateOnly) else GameHelper:ApplyBuffTo(cardObj,cardObj.cardGUI,"SPELLPWR",self.data.spellPWR,0.25,simulateOnly) end end, funcOnCreatingThisTagOnUnit=function(unitTag) local typeName=unitTag.data.split[2] if unitTag and not simulateOnly then if typeName=="UP" then unitTag.spr=492 else unitTag.spr=261 end end end }, BUFF={spr=267,data={split={}},desc={{c=15,str="Stat is increased"}}, genDesc=function(self,cardObj) return {{c=15,str=self.desc[1].str.." by "..(self.data.spellPWR or 0)}} end, genName=function(self,cardObj) return {self.name,(self.data.split[2] or ""),"+"..(self.data.spellPWR or 0)} end, funcOnRemovingThisTag=function(self,cardObj,simulateOnly) local isMana=false if self.data.split and self.data.split[2] then isMana=(self.data.split[2]=="MANA") if isMana and (not simulateOnly) then if not cardObj.isLeaderCard then cardObj=(cardObj.isPlayerCard and GameHelper.playerLeaderCard or GameHelper.enemyLeaderCard) end end end if not isMana then GameHelper:ApplyCutTo(cardObj,cardObj.cardGUI,self.data.split[2],self.data.spellPWR,0.25,simulateOnly) end end, funcAfterBeingSummoned=function(self,cardObj,simulateOnly) --for units that start with this tag be default --TODO: refactor this as this is copy of funcOnRemovingThisTag but with opposite spell --to allow proper init for units that start with this tag local isMana=false if self.data.split and self.data.split[2] then isMana=(self.data.split[2]=="MANA") if isMana and (not simulateOnly) then if not cardObj.isLeaderCard then cardObj=(cardObj.isPlayerCard and GameHelper.playerLeaderCard or GameHelper.enemyLeaderCard) end end end if not isMana then GameHelper:ApplyBuffTo(cardObj,cardObj.cardGUI,self.data.split[2],self.data.spellPWR,0.25,simulateOnly) end end, funcOnCreatingThisTagOnUnit=onBuffTagCreationFunc, }, CUT={spr=283,data={split={}},desc={{c=15,str="Stat is decreased"}}, genDesc=function(self,cardObj) return {{c=15,str=self.desc[1].str.." by "..("-"..(self.data.spellPWR or 0))}} end, funcOnRemovingThisTag=function(self,cardObj,simulateOnly) local isMana=false if self.data.split and self.data.split[2] then isMana=self.data.split[2]=="MANA" if isMana and not simulateOnly then if not cardObj.isLeaderCard then cardObj=(cardObj.isPlayerCard and GameHelper.playerLeaderCard or GameHelper.enemyLeaderCard) end end end if not isMana then GameHelper:ApplyBuffTo(cardObj,cardObj.cardGUI,self.data.split[2],self.data.spellPWR,0.25,simulateOnly) end end, funcAfterBeingSummoned=function(self,cardObj,simulateOnly) --for units that start with this tag be default local isMana=false if self.data.split and self.data.split[2] then isMana=self.data.split[2]=="MANA" if isMana and not simulateOnly then if not cardObj.isLeaderCard then cardObj=(cardObj.isPlayerCard and GameHelper.playerLeaderCard or GameHelper.enemyLeaderCard) end end end if not isMana then GameHelper:ApplyCutTo(cardObj,cardObj.cardGUI,self.data.split[2],self.data.spellPWR,0.25,simulateOnly) end end, genName=function(self,cardObj) return {self.name,(self.data.split[2] or ""),"-"..(self.data.spellPWR and self.data.spellPWR or 0)} end, funcOnCreatingThisTagOnUnit=onCutTagCreationFunc,}, } glUnitTagsByUID={} local genNameAsStr=function(self,cardObj) local t=self:genName(cardObj) local s="" local i=0 foreach(t,function(str) s=s..(i>0 and " " or "")..str i=i+1 end) return s end foreach(glUnitTags,function(tag) tag.genNameAsStr=genNameAsStr table.insert(glUnitTagsByUID,tag) end) glSpellsTags={ DEFAULT={spr=511,data={},desc={{c=10,str="This is unknown TAG and isn't supported by the game at this moment"}}, genDesc=function(self,cardObj) return self.desc end, genName=function(self,cardObj) return {self.name} end, }, DAMAGE={spr=508,data={split={}},canTarget={glGameTarget.ANY_UNIT,glGameTarget.ANY_LEADER}, desc={{c=15,str=" damage will be dealt to"},{c=3,str="Where value is equal to SPELLPWR of the card"}}, genDesc=function(self,cardObj) return {{c=15,str=(cardObj and cardObj.stats.spellPower.cur or 0)..self.desc[1].str..(self.data.split[2]=="UNIT" and " the target unit" or " ALL UNITS")},self.desc[2]} end, funcOnCast=function(self,castingCardObj,targetCardObj,castingCardGUI,targetCardGUI,simulateOnly) local spellPWR=castingCardObj.stats.spellPower.cur spellPWR=spellPWR+GameHelper:FindAmountOfSpellPowerOnBattlefield(castingCardObj.isPlayerCard) local dmgUnit=function() if not simulateOnly and castingCardGUI and targetCardGUI then ParticleHelper:CreateFireballFX(castingCardGUI:getCenterX(),castingCardGUI.y,targetCardGUI:getCenterX(),targetCardGUI.y,math.floor(spellPWR/2)) end GameHelper:ApplyDamageTo(targetCardObj,targetCardGUI,cardGUI,spellPWR,0.25,simulateOnly) end if self.data.split[2]=="UNIT" then dmgUnit() else if simulateOnly then --only show preview on unit that is target dmgUnit() else local units={GameHelper.playerLeaderCard,GameHelper.enemyLeaderCard} foreach(GameHelper.playerBattlefieldCards,function(unitObj) if unitObj then table.insert(units,unitObj) end end) foreach(GameHelper.enemyBattlefieldCards,function(unitObj) if unitObj then table.insert(units,unitObj) end end) foreach(units,function(unitObj) local unitGUI=unitObj.cardGUI if not simulateOnly and castingCardGUI and unitGUI then ParticleHelper:CreateFireballFX(castingCardGUI:getCenterX(),castingCardGUI.y,unitGUI:getCenterX(),unitGUI.y,math.floor(spellPWR/2)) end GameHelper:ApplyDamageTo(unitObj,unitGUI,nil,spellPWR,0.25,simulateOnly) end) end end end, genName=function(self,cardObj) return {self.name,self.data.split[2]} end, }, WAVE={spr=508,data={},canTarget={glGameTarget.ANY_UNIT,glGameTarget.ANY_LEADER}, desc={{c=15,str=" damage will be dealt to the target"},{c=14,str="And half of that damage will be dealt to adjacent units"},{c=3,str="Where value is equal to SPELLPWR of card"}}, genDesc=function(self,cardObj) return {{c=self.desc[1].c,str=(cardObj and cardObj.stats.spellPower.cur+GameHelper:FindAmountOfSpellPowerOnBattlefield(cardObj.isPlayerCard) or 0)..self.desc[1].str},self.desc[2]} end, funcOnCast=function(self,castingCardObj,targetCardObj,castingCardGUI,targetCardGUI,simulateOnly) local spellPower=castingCardObj.stats.spellPower.cur spellPower=spellPower+GameHelper:FindAmountOfSpellPowerOnBattlefield(castingCardObj.isPlayerCard) GameHelper:ApplyDamageTo(targetCardObj,targetCardGUI,cardGUI,spellPower,0.25,simulateOnly) if not simulateOnly then if castingCardGUI and targetCardGUI then ParticleHelper:CreateFireballFX(castingCardGUI:getCenterX(),castingCardGUI.y,targetCardGUI:getCenterX(),spellPower) end foreach(GameHelper:GetAdjacentUnitsToProvided((targetCardObj.isPlayerCard and GameHelper.playerBattlefieldCards or GameHelper.enemyBattlefieldCards),targetCardObj), function(battleCardObj) if battleCardObj then local bCGUI=battleCardObj.cardGUI if bCGUI then AsyncQueueLogicHelper:AddToQueue(function(data) local targetGUI = data.targetCardGUI local bcGUI = data.bCGUI GameHelper:ApplyDamageTo(data.battleCardObj,bcGUI,data.cardGUI,math.floor(spellPower/2),0,simulateOnly) if targetGUI and bcGUI then ParticleHelper:CreateFireballFX(targetGUI:getCenterX(),targetGUI:getCenterY(),bcGUI:getCenterX(),bcGUI:getCenterY(),math.floor(data.spellPower/2)) end end,{bCGUI=bCGUI,targetCardGUI=targetCardGUI,battleCardObj=battleCardObj,castingCardObj=castingCardObj,spellPower=spellPower},0.3) end end end) end end, genName=function(self,cardObj) return {self.name} end, }, HEAL={spr=507,data={},canTarget={glGameTarget.ANY_UNIT,glGameTarget.ANY_LEADER},desc={{c=15,str=" HP will be restored to the target"},{c=3,str="Where value is equal to SPELLPWR of card"}}, genDesc=function(self,cardObj) return {{c=self.desc[1].c,str=(cardObj and cardObj.stats.spellPower.cur+GameHelper:FindAmountOfSpellPowerOnBattlefield(cardObj.isPlayerCard) or 0)..self.desc[1].str},self.desc[2]} end, funcOnCast=function(self,castingCardObj,targetCardObj,castingCardGUI,targetCardGUI,simulateOnly) local spellPower=castingCardObj.stats.spellPower.cur spellPower=spellPower+GameHelper:FindAmountOfSpellPowerOnBattlefield(castingCardObj.isPlayerCard) GameHelper:ApplyHealTo(targetCardObj,targetCardGUI,spellPower,0.25,simulateOnly) end, genName=function(self,cardObj) return {self.name} end, }, MANAREST={spr=259,data={},canTarget={glGameTarget.ANY_LEADER},desc={{c=15,str=" MANA will be restored for the target leader"},{c=3,str="Where value is equal to SPELLPWR of card"}}, genDesc=function(self,cardObj) return {{c=self.desc[1].c,str=(cardObj and cardObj.stats.spellPower.cur+GameHelper:FindAmountOfSpellPowerOnBattlefield(cardObj.isPlayerCard) or 0)..self.desc[1].str},self.desc[2]} end, funcOnCast=function(self,castingCardObj,targetCardObj,castingCardGUI,targetCardGUI,simulateOnly) local leaderGUI=targetCardObj.isPlayerCard and GUIHelper.playerLeaderCard or GUIHelper.enemyLeaderCard local leaderCardObj=targetCardObj.isPlayerCard and GameHelper.playerLeaderCard or GameHelper.enemyLeaderCard if not simulateOnly and leaderGUI then ParticleHelper:CreateManaRestFX(leaderGUI:getCenterX(),leaderGUI:getCenterY(),0.25) end local spellPower=castingCardObj.stats.spellPower.cur spellPower=spellPower+GameHelper:FindAmountOfSpellPowerOnBattlefield(castingCardObj.isPlayerCard) leaderCardObj:RestoreMana(spellPower,false) end, genName=function(self,cardObj) return {self.name} end,}, ARMORBUFF_TUTORIAL={spr=505,data={},canTarget={glGameTarget.ANY_UNIT},desc={{c=15,str=" ARMOR will be added for the target"},{c=3,str="Where value is equal to SPELLPWR of card"}}, genDesc=function(self,cardObj) return {{c=self.desc[1].c,str=(cardObj and cardObj.stats.spellPower.cur+GameHelper:FindAmountOfSpellPowerOnBattlefield(cardObj.isPlayerCard) or 0)..self.desc[1].str},self.desc[2]} end, funcOnCast=function(self,castingCardObj,targetCardObj,castingCardGUI,targetCardGUI,simulateOnly) local t=deepcopy(glSpellsTags.BUFF) t.data.spellPWR=castingCardObj.stats.spellPower.cur t.data.split={"BUFF","ARMOR"} if t.funcOnCreatingThisTagOnUnit then t:funcOnCreatingThisTagOnUnit(castingCardObj,simulateOnly) end t:funcOnCast(castingCardObj,targetCardObj,castingCardGUI,targetCardGUI,simulateOnly) end, genName=function(self,cardObj) return {"ARMORBUFF","TUTORIAL"} end,}, BUFF={spr=267,data={split={}},canTarget={glGameTarget.ANY_UNIT,glGameTarget.ANY_LEADER},desc={{c=15,str=" will be added for the target"},{c=3,str="Where value is equal to SPELLPWR of card"}}, genDesc=function(self,cardObj) return {{c=self.desc[1].c,str=(cardObj and cardObj.stats.spellPower.cur+GameHelper:FindAmountOfSpellPowerOnBattlefield(cardObj.isPlayerCard) or 0).." "..(self.data.split[2] or "")..self.desc[1].str},self.desc[2]} end, genName=function(self,cardObj) return {self.name,(self.data.split[2] or ""),((cardObj and cardObj.stats) and "+"..cardObj.stats.spellPower.cur+GameHelper:FindAmountOfSpellPowerOnBattlefield(cardObj.isPlayerCard) or "")} end, funcOnCast=function(self,castingCardObj,targetCardObj,castingCardGUI,targetCardGUI,simulateOnly) local spellPower=castingCardObj.stats.spellPower.cur spellPower=spellPower+GameHelper:FindAmountOfSpellPowerOnBattlefield(castingCardObj.isPlayerCard) local typeName=self.data.split[2] local unitTag=glUnitTags["BUFF"] local isMana=false if unitTag then unitTag=deepcopy(glUnitTags["BUFF"]) if typeName=="ARMOR" then unitTag.spr=505 elseif typeName=="ATK" then unitTag.spr=506 elseif typeName=="MANA" then isMana=true if (not simulateOnly) then if not targetCardObj.isLeaderCard then targetCardObj=(targetCardObj.isPlayerCard and GameHelper.playerLeaderCard or GameHelper.enemyLeaderCard) targetCardGUI=targetCardObj.cardGUI end end unitTag.spr=499 elseif typeName=="HP" then unitTag.spr=504 elseif typeName=="SPELLPWR" then unitTag.spr=492 spellPower=castingCardObj.stats.spellPower.cur end if not isMana then GameHelper:ApplyBuffTo(targetCardObj,targetCardGUI,typeName,spellPower,0.25,simulateOnly) if not simulateOnly then unitTag.data.spellPWR=spellPower unitTag.data.split=self.data.split if unitTag.funcOnCreatingThisTagOnUnit then unitTag:funcOnCreatingThisTagOnUnit(targetCardObj,simulateOnly) end targetCardObj:InsertTag(unitTag,simulateOnly) end end end end, funcOnCreatingThisTagOnUnit=onBuffTagCreationFunc,}, CUT={spr=283,data={split={}},canTarget={glGameTarget.ANY_UNIT,glGameTarget.ANY_LEADER},desc={{c=15,str=" will be removed from the target"},{c=3,str="Where value is equal to SPELLPWR of card"}}, genDesc=function(self,cardObj) return {{c=self.desc[1].c,str=(cardObj and cardObj.stats.spellPower.cur+GameHelper:FindAmountOfSpellPowerOnBattlefield(cardObj.isPlayerCard) or 0).." "..(self.data.split[2] or "")..self.desc[1].str},self.desc[2]} end, funcOnCast=function(self,castingCardObj,targetCardObj,castingCardGUI,targetCardGUI,simulateOnly) local spellPower=castingCardObj.stats.spellPower.cur spellPower=spellPower+GameHelper:FindAmountOfSpellPowerOnBattlefield(castingCardObj.isPlayerCard) local typeName=self.data.split[2] local unitTag=glUnitTags["CUT"] local isMana=false if unitTag then unitTag=deepcopy(unitTag) if typeName=="ARMOR" then unitTag.spr=500 elseif typeName=="ATK" then unitTag.spr=501 elseif typeName=="MANA" then isMana=true if (not simulateOnly) then if not targetCardObj.isLeaderCard then targetCardObj=(targetCardObj.isPlayerCard and GameHelper.playerLeaderCard or GameHelper.enemyLeaderCard) targetCardGUI=targetCardObj.cardGUI end end unitTag.spr=502 elseif typeName=="HP" then unitTag.spr=503 elseif typeName=="SPELLPWR" then unitTag.spr=261 spellPower=castingCardObj.stats.spellPower.cur end if not isMana then GameHelper:ApplyCutTo(targetCardObj,targetCardGUI,typeName,spellPower,0.25,simulateOnly) if not simulateOnly then unitTag.data.spellPWR=spellPower unitTag.data.split=self.data.split if unitTag.funcOnCreatingThisTagOnUnit then unitTag:funcOnCreatingThisTagOnUnit(targetCardObj,simulateOnly) end targetCardObj:InsertTag(unitTag,simulateOnly) end end end end, genName=function(self,cardObj) return {self.name,(self.data.split[2] or ""),((cardObj and cardObj.stats) and "-"..cardObj.stats.spellPower.cur+GameHelper:FindAmountOfSpellPowerOnBattlefield(cardObj.isPlayerCard) or "")} end, funcOnCreatingThisTagOnUnit=onCutTagCreationFunc, }, SPELLPWR={spr=267,data={split={}},canTarget={glGameTarget.ANY_UNIT,glGameTarget.ANY_LEADER},desc={{c=15,str="SPELLPWR will be"},{c=15,str="for the target"},{c=9,str="and it will affect *EVERY* card that uses SPELLPWR"},{c=9,str="except this one"},}, genName=function(self,cardObj) return {self.name,(self.data.split[2] or ""),(self.data.split[2]=="UP" and "+" or "-")..self.data.spellPWR} end, genDesc=function(self,cardObj) return {{c=15,str=self.desc[1].str..(self.data.split[2]=="UP" and "increased" or "decreased").." by "..(self.data.spellPWR or 0)..self.desc[2].str},{c=9,str=self.desc[3].str}} end, funcOnCast=function(self,castingCardObj,targetCardObj,castingCardGUI,targetCardGUI,simulateOnly) local spellPower=castingCardObj.stats.spellPower.cur spellPower=spellPower+GameHelper:FindAmountOfSpellPowerOnBattlefield(castingCardObj.isPlayerCard) local typeName=self.data.split[2] local unitTag=glUnitTags["SPELLPWR"] if unitTag then unitTag=deepcopy(unitTag) spellPower=castingCardObj.stats.spellPower.cur if self.data.split[2]=="UP" then GameHelper:ApplyBuffTo(targetCardObj,targetCardGUI,"SPELLPWR",spellPower,0.25,simulateOnly) else GameHelper:ApplyCutTo(targetCardObj,targetCardGUI,"SPELLPWR",spellPower,0.25,simulateOnly) end if not simulateOnly then unitTag.data.spellPWR=spellPower unitTag.data.split=self.data.split if unitTag.funcOnCreatingThisTagOnUnit then unitTag:funcOnCreatingThisTagOnUnit(targetCardObj,simulateOnly) end targetCardObj:InsertTag(unitTag,simulateOnly) end end end, funcOnCreatingThisTagOnUnit=function(unitTag) local typeName=unitTag.data.split[2] if unitTag and not simulateOnly then if typeName=="UP" then unitTag.spr=492 else unitTag.spr=261 end end end }, DRAW={spr=493,data={},canTarget={glGameTarget.ANY_LEADER},desc={{c=15,str=" cards will be drawn for target unit leader"},{c=3,str="Where value is equal to SPELLPWR"}}, genDesc=function(self,cardObj) return {{c=self.desc[1].c,str=(cardObj and cardObj.stats.spellPower.cur+GameHelper:FindAmountOfSpellPowerOnBattlefield(cardObj.isPlayerCard) or 0)..self.desc[1].str},self.desc[2]} end, funcOnCast=function(self,castingCardObj,targetCardObj,castingCardGUI,targetCardGUI,simulateOnly) for i=1,castingCardObj.stats.spellPower.cur+GameHelper:FindAmountOfSpellPowerOnBattlefield(castingCardObj.isPlayerCard) do AsyncQueueLogicHelper:AddToQueue(function(data) if not simulateOnly then GameHelper:ExecuteDrawCard(data.cardObj.isPlayerCard) end end,{cardObj=targetCardGUI},0.5+i*0.5) end end, genName=function(self,cardObj) return {self.name..((cardObj and cardObj.stats) and " ("..cardObj.stats.spellPower.cur+GameHelper:FindAmountOfSpellPowerOnBattlefield(cardObj.isPlayerCard)..")" or "")} end, }, FIND={spr=509,data={},canTarget={glGameTarget.ANY_LEADER},desc={{c=15,str="Choose 1 card from top 3 cards"},{c=15,str="from target unit deck on casting"},{c=15,str="to add to your hand"}}, genDesc=function(self,cardObj) return self.desc end,funcOnCast=function(self,castingCardObj,targetCardObj,castingCardGUI,targetCardGUI,simulateOnly) AsyncQueueLogicHelper:AddToQueue(function(data) if not simulateOnly then local player=data.castingCardGUI.isPlayerCard if player then local playerCards=data.targetCardGUI.isPlayerCard local cards={} local deck=playerCards and GameHelper.playerDeckCards or GameHelper.enemyDeckCards for i=1,3 do table.insert(cards,deck[i]) end local i=1 if not glFindCardTagGUI then GUICreator:CreateFindTagDialog() end foreach(glFindCardTagGUI.cards,function(cardGUI) cardGUI.cardObj=cards[i] i=i+1 end) glFindCardTagGUI.deckToDrawFrom=deck glFindCardTagGUI:show() else GameHelper:ExecuteDrawCard(false) end end end,{castingCardGUI=castingCardGUI,targetCardGUI=targetCardGUI},0.25) end, genName=function(self,cardObj) return {self.name} end,}, REMOVETAG={spr=510,data={},canTarget={glGameTarget.ANY_UNIT,glGameTarget.ANY_LEADER},desc={{c=15,str=" TAG(s) from target unit"},{c=3,str="where number is equal to SPELLPWR"}}, genDesc=function(self,cardObj) local posID=self.data.split[2] return {{c=15,str="Remove "..((posID and posID=="FIRST") and "first " or "last ")..(cardObj and cardObj.stats.spellPower.cur or 0)..self.desc[1].str},self.desc[2]} end, funcOnCast=function(self,castingCardObj,targetCardObj,castingCardGUI,targetCardGUI,simulateOnly) for i=1,castingCardObj.stats.spellPower.cur do if #targetCardObj.tags>0 then local posID=self.data.split[2] local pID=(posID=="FIRST" and 1 or #targetCardObj.tags) local tag=targetCardObj:GetTagByPos(pID) if tag then targetCardObj:RemoveTagByObj(tag,simulateOnly) end end end end, genName=function(self,cardObj) return {self.name,self.data.split[2]} end, }, APPLY={spr=17,data={},canTarget={glGameTarget.ANY_UNIT,glGameTarget.ANY_LEADER},desc={{c=15,str="Applies the specified tag on the target unit"}}, genDesc=function(self,cardObj) local tag=glUnitTags[self.data.split[2]] if tag then local d={} table.insert(d,self.desc[1]) table.insert(d,{c=09,str=self.data.split[2]}) foreach(tag.desc,function(line) table.insert(d,line) end) return d end return self.desc end, funcOnCast=function(self,castingCardObj,targetCardObj,castingCardGUI,targetCardGUI,simulateOnly) local unitTag=deepcopy(glUnitTags[self.data.split[2]]) if unitTag then if unitTag.funcOnCreatingThisTagOnUnit then unitTag:funcOnCreatingThisTagOnUnit(targetCardObj,simulateOnly) end targetCardObj:InsertTag(unitTag,simulateOnly) end end, genName=function(self,cardObj) return {self.name,self.data.split[2]} end, }, SUMMON={spr=495,data={split={}},canTarget={glGameTarget.ANY_UNIT,glGameTarget.ANY_LEADER},desc={{c=15,str=" unit(s) will be summoned with ID provided on casting"},{c=15,str="at first empty space, starting from left"},{c=15,str="for the side of target unit"},{c=3,str="Where number is equal to SPELLPWR"}}, genDesc=function(self,cardObj) return {{c=self.desc[1].c,str=(cardObj and cardObj.stats.spellPower.cur or 0)..self.desc[1].str},self.desc[2], self.desc[3], self.desc[4]} end, funcOnCast=function(self,castingCardObj,targetCardObj,castingCardGUI,targetCardGUI,simulateOnly) for j=1,castingCardObj.stats.spellPower.cur do AsyncQueueLogicHelper:AddToQueue(function(data) local cardID=data.split[2] if cardID and GameHelper.allCards[cardID] then local isPlayer=data.cardObj.isPlayerCard local n=0 for i=1,6 do local bf=(isPlayer and GameHelper.playerBattlefieldCards or GameHelper.enemyBattlefieldCards) if not bf[i] then n=i break end end if n>0 then if not simulateOnly then local unit=GameHelper:SummonUnitOntoBattlefield(GameHelper.allCards[cardID]:DeepCopy(),n,isPlayer) if unit then local unitTag=deepcopy(glUnitTags["SUMMONED"]) unit:InsertTag(unitTag,simulateOnly) end end end end end,{split=self.data.split,cardObj=targetCardObj},0.5+j*0.5) end end, genName=function(self,cardObj) return {self.name,self.data.split[2]} end, }, STEALTAG={spr=486,data={split={}},canTarget={glGameTarget.ANY_UNIT,glGameTarget.ANY_LEADER},desc={{c=15,str=" TAG(s) will be stolen from target unit"},{c=15,str="and appied to caster leader unit"},{c=3,str="Where value is equal to SPELLPWR"}}, genDesc=function(self,cardObj) local posID=self.data.split[2] return {{c=15,str=((posID and posID=="FIRST") and "first " or "last ")..(cardObj and cardObj.stats.spellPower.cur or 0)..self.desc[1].str},self.desc[2],self.desc[3]} end, funcOnCast=function(self,castingCardObj,targetCardObj,castingCardGUI,targetCardGUI,simulateOnly) for i=1,castingCardObj.stats.spellPower.cur do if #targetCardObj.tags>0 then local posID=self.data.split[2] local pID=(posID=="FIRST" and 1 or #targetCardObj.tags) local tag=targetCardObj:GetTagByPos(pID) if tag then targetCardObj:RemoveTagByObj(tag,simulateOnly) --TODO: this requires to simulate leader as well. look into simulations doing whole board of simulation instead of 2 units only? if not simulateOnly then local leaderUnit=(not castingCardObj.isPlayerCard and GameHelper.playerLeaderCard or GameHelper.enemyLeaderCard) leaderUnit:InsertTag(tag,simulateOnly) end end end end end, genName=function(self,cardObj) return {self.name,self.data.split[2]} end,}, } foreach(glSpellsTags,function(tag) tag.genNameAsStr=genNameAsStr end) local rh=RuleHelper rh.maxManaCount=9 rh.maxCardsInDeck=24 rh.startHandSize=4 rh.numberOfActiveTagsInUnit=3 rh.numberOfActiveTagsInLeader=6 rh.modeStartingLives=2 rh.hpPerPoint=2 rh.armorPerPoint=2 rh.atkPerPoint=0.5 rh.pointsToAllocate=6 rh.maxArtifactsPerRun=6 local sh=ScoreHelper sh.takingNoRewardMultValue=1.1 sh.AIDifficultyMultValue=1.2 sh.losingLifeMultValue=0.15 sh.notLosingLifeMultValue=1.5 sh.gameWonValue=10000 sh.matchWonValue=1000 sh.dealtDamageValue=1 sh.unitDiedValue=1 sh.unitKilledValue=2 sh.leadersKilledValue=1000 sh.receivedDamageToLeaderValue=-1 sh.turnSurvivedValue=10 sh.unitKillValue=10 sh.dealtDamageScore=0 sh.unitDiedScore=0 sh.unitKilledScore=0 sh.leadersKilledScore=0 sh.receivedDamageToLeaderScore=0 sh.turnSurvivedScore=0 EventHelper:RegisterListenerToEvent(glEventTypes.UNIT_DIED,sh,function(eventID,callerObj,simulateOnly,valuesArray) if simulateOnly then return end local sh=ScoreHelper sh.unitDiedScore=sh.unitDiedScore+1 local killedByUnitObj=valuesArray.initingObj local unitKilledObj=valuesArray.cardObj if killedByUnitObj and killedByUnitObj.isPlayerCard then sh.unitKilledScore=sh.unitKilledScore+1 end if unitKilledObj.isLeaderCard and not unitKilledObj.isPlayerCard then sh.leadersKilledScore=sh.leadersKilledScore+1 end end) EventHelper:RegisterListenerToEvent(glEventTypes.DAMAGE_DEALT,sh,function(eventID,callerObj,simulateOnly,valuesArray) if simulateOnly then return end local sh=ScoreHelper sh.dealtDamageScore=sh.dealtDamageScore+valuesArray.amountDealt local dealtDMGToObj=valuesArray.cardObj if dealtDMGToObj.isLeaderCard and dealtDMGToObj.isPlayerCard then sh.receivedDamageToLeaderScore=valuesArray.amountDealt end end) EventHelper:RegisterListenerToEvent(glEventTypes.TURN_ENDED,sh,function(eventID,callerObj,simulateOnly,valuesArray) if simulateOnly then return end GameHelper.turnCounter=GameHelper.turnCounter+1 GameHelper.allturnsCounter=GameHelper.allturnsCounter+1 ScoreHelper.turnSurvivedScore=ScoreHelper.turnSurvivedScore+1 end) local gh=GameHelper gh.isfirstBattle=true gh.cardGUIElemHoveredOver=nil gh.cardGUIElemSelected=nil gh.playerLeaderCard=nil gh.enemyLeaderCard=nil gh.cardGUIHoveredTime=0 gh.gameModeDifficulty=1 gh.animationSpeed=2 gh.controlScheme=1 gh.delayBeforeShowingTooltips=0.5 gh.delayBeforeShowingWhyCantAttack=0.1 gh.delayBeforeShowingFullCard=0.5 gh.showFullCardPreviewInBattle=0 gh.allDeckTemplates={} gh.allCards={} gh.playerHandCards={} gh.playerDeckCards={} gh.enemyHandCards={} gh.enemyDeckCards={} gh.playerBattlefieldCards={} gh.enemyBattlefieldCards={} gh.playerChoosenCards=false gh.isPlayerTurn=true gh.currentGameState=glGameStates.START_TURN gh.playerNumOfTurnsWithoutCards=0 gh.currentPlayerLives=RuleHelper.modeStartingLives gh.maxPlayerLives=RuleHelper.modeStartingLives gh.lostPlayerLives=0 gh.allturnsCounter=1 gh.artifactsEncounterLvl=0 gh.enemyNumOfTurnsWithoutCards=0 gh.turnCounter=1 gh.highestGameScore=pmem(255) --TODO save space by moving one number to located in the second half of one uint gh.numOfWinningGameMode=pmem(254) gh.numOfPlayingGameMode=pmem(253) gh.lastNumOfWinningGameMode=gh.numOfWinningGameMode gh.lastNumOfPlayingGameMode=gh.numOfPlayingGameMode local text1="Which can be found at " local t21="'CHOOSE STARTING DECK' screen" local t22="'CREATE YOUR LEADER' screen" local t23="'CHOOSE ARTIFACT' screen" local t24="'INVENTORY' screen" AchievementsHelper.unlocksData={ DECK1={name="HUMAN DECK",desc={text1..t21},req="PLAY",type="DECK",reqVal=1}, DECK2={name="UNDEAD DECK",desc={text1..t21},req="PLAY",type="DECK",reqVal=2}, DECK3={name="DASH DECK",desc={text1..t21},req="PLAY",type="DECK",reqVal=3}, DECK4={name="DISTRACT DECK",desc={text1..t21},req="PLAY",type="DECK",reqVal=4}, DECK5={name="RANGED DECK",desc={text1..t21},req="PLAY",type="DECK",reqVal=5}, DECK6={name="FEARED DECK",desc={text1..t21},req="WIN",type="DECK",reqVal=1}, DECK7={name="VENOM/POISON DECK",desc={text1..t21},req="WIN",type="DECK",reqVal=2}, DECK8={name="PURE MAGE DECK",desc={text1..t21},req="WIN",type="DECK",reqVal=3}, CHANGE_LEADER_AVATAR={name="CHANGE LEADER AVATAR",desc={text1.."as first screen when starting new game from now on"},req="PLAY",type="MECHANICS",reqVal=0}, CHANGE_LEADER_STATS={name="CHANGE LEADER STATS",desc={text1..t22},req="PLAY",type="MECHANICS",reqVal=1}, CHANGE_LEADER_TAGS={name="CHANGE LEADER TAGS",desc={text1..t22},req="PLAY",type="MECHANICS",reqVal=2}, INVENTORY_REMOVE_CARDS={name="INVENTORY REMOVE CARDS",desc={text1..t24},req="PLAY",type="MECHANICS",reqVal=3}, TAG2={name="POISON TAG",desc={text1..t22},req="PLAY",type="TAG",reqVal=3}, TAG3={name="FEARED TAG",desc={text1..t22},req="PLAY",type="TAG",reqVal=4}, TAG4={name="VENOM TAG",desc={text1..t22},req="PLAY",type="TAG",reqVal=5}, TAG5={name="SPELLPWR_DOWN TAG",desc={text1..t22},req="WIN",type="TAG",reqVal=10}, TAG6={name="STEAL TAG",desc={text1..t22},req="WIN",type="TAG",reqVal=4}, TAG7={name="SPELLPWR_UP TAG",desc={text1..t22},req="WIN",type="TAG",reqVal=2}, TAG8={name="DISTRACT TAG",desc={text1..t22},req="WIN",type="TAG",reqVal=6}, TAG9={name="SLOW TAG",desc={text1..t22},req="WIN",type="TAG",reqVal=7}, TAG10={name="POISONED TAG",desc={text1..t22},req="WIN",type="TAG",reqVal=8}, ARTIFACT1={name="REDRAW CARDS ARTIFACT",objID="SELECT_STARTING_CARDS",desc={text1..t23},req="PLAY",type="ARTIFACT",reqVal=6}, ARTIFACT2={name="ANKH ARTIFACT",objID="REVIVE_ANKH",desc={text1..t23},req="PLAY",type="ARTIFACT",reqVal=7}, ARTIFACT3={name="2 BUCKETS ARTIFACT",objID="ADDITIONAL_CARD_BUCKETS",desc={text1..t23},req="WIN",type="ARTIFACT",reqVal=8}, } AchievementsHelper.closestUnlocksData={ } local lastUnlocked=false local lastNotUnlocked=nil local playedTimes=gh.numOfPlayingGameMode local wonTimes=gh.numOfWinningGameMode local didntPlayBefore=playedTimes==0 local pN=1 local wN=1 Logger:Debug("Played:"..playedTimes..";Won:"..wonTimes,glMsgType.INIT_BASE) foreach(AchievementsHelper.unlocksData,function(uData,key) uData.id=key local isPlay=(uData.req=="PLAY") uData.showDialog=false uData.unlocked=(isPlay and gh.numOfPlayingGameMode or gh.numOfWinningGameMode)>=uData.reqVal if not uData.unlocked and ((uData.reqVal-(isPlay and playedTimes or wonTimes))==1) then table.insert(AchievementsHelper.closestUnlocksData,uData) lastNotUnlocked=uData.req end lastUnlocked=uData.unlocked if uData.objID then local artifact=glLeaderArtifacts[uData.objID] if artifact then artifact.enabled=artifact.enabled and uData.unlocked end end Logger:Trace(uData.name..";uData.reqVal:"..uData.reqVal..";unlocked:"..(uData.unlocked and 1 or 0),glMsgType.INIT_BASE) end) AchievementsHelper.CreateLeaderScreenUnlocked=AchievementsHelper.unlocksData.CHANGE_LEADER_AVATAR.unlocked AchievementsHelper.CreateLeaderSelectTagsUnlocked=AchievementsHelper.unlocksData.CHANGE_LEADER_TAGS.unlocked AchievementsHelper.CreateLeaderTweakStatsUnlocked=AchievementsHelper.unlocksData.CHANGE_LEADER_STATS.unlocked AchievementsHelper.RemoveCardsUnlocked=AchievementsHelper.unlocksData.INVENTORY_REMOVE_CARDS.unlocked gh.finishedCreatingLeader=not AchievementsHelper.CreateLeaderScreenUnlocked local ah=AIHelper ah.styleOfPlay=0 ah.AIDifficulty=1 ah.AISpeedMult=1 ah.aiTimeForTurnInSecs=2.6-(AIHelper.AISpeedMult-3)*0.4 ah.aiTimeForTurnInSecsBase=AIHelper.aiTimeForTurnInSecs ah.aiTimeForTurnInSecsCur=AIHelper.aiTimeForTurnInSecs ah.aiTimeBetweenActionsInSecs=1.6-(AIHelper.AISpeedMult-2)*0.5 ah.aiMaxTimeForTurnInSecs=AIHelper.aiTimeBetweenActionsInSecs*8+0.6 ah.aiTurnTimeCur=0 ah.aiDelayBeforeTurnAmount=0.5 ah.aiDelayBeforeTurn=ah.aiDelayBeforeTurnAmount ah.aiTurnTimeOfNextAction=AIHelper.aiTimeBetweenActionsInSecs ah:SetMoveDesc("") ah.doNothingCounter=0 ah.stopUpdatingAI=false gh.gamesWon=0 Logger:Debug("PARSING glUnitsCSVNames",glMsgType.INIT_BASE) local unitsCSVColumnsNames=explode_internal(glUnitsCSVNames) Logger:Debug("PARSING glUnitsCSVData",glMsgType.INIT_BASE) glCSVUnitsCardsByOrder=explode_internal(glUnitsCSVData,unitsCSVColumnsNames) glCSVUnitsCardsByID={} local i=1 foreach(glUnitTags,function(tag,key) tag.name=key end) foreach(glSpellsTags,function(tag,key) tag.name=key end) foreach(glLeaderArtifacts,function(tag,key) tag.id=key end) foreach(glCardBuckets,function(tag,key) tag.id=key tag.name=key end) local deck={} foreach(glCSVUnitsCardsByOrder,function(temp) if not temp.id then return end if not temp.turnedOff then if temp.tags~=nil then temp.tags=string.split(temp.tags,",") else temp.tags={} end local splitTags=temp.tags temp.tags={} foreach(splitTags,function(tagName) local tagEntry=nil if glUnitTags[tagName] then tagEntry=deepcopy(glUnitTags[tagName]) tagEntry.data=deepcopy(tagEntry.data) else if string.find(tagName,"_") then local split=string.split(tagName,"_") Logger:Trace("unit tag with split:"..tagName,glMsgType.INIT_BASE) if glUnitTags[split[1]] then tagEntry=deepcopy(glUnitTags[split[1]]) tagÅEntry.data=deepcopy(tagEntry.data) tagEntry.data.spellPWR=1 tagEntry.data.split=split Logger:Trace("added split table:{",glMsgType.INIT_BASE) foreach(split,function(spl) Logger:Trace(" "..spl,glMsgType.INIT_BASE) end) Logger:Trace("}",glMsgType.INIT_BASE) if tagEntry.funcOnCreatingThisTagOnUnit then tagEntry:funcOnCreatingThisTagOnUnit(nil) end end else tagEntry=deepcopy(glUnitTags.DEFAULT) end end table.insert(temp.tags,tagEntry) end) glCSVUnitsCardsByID[temp.id]=temp local card=CardClass(temp.id,temp.name,temp.sprite,temp.tags,temp.rarity,temp.desc,gh:InitUnitCardStatsTable(temp.hp,temp.armor,temp.attack,temp.manaCost)) gh.allCards[temp.id]=card table.insert(deck,temp.id) i=i+1 else Logger:Debug("NOT PROCESSING UNIT:"..temp.id, glMsgType.INIT_BASE) end end) Logger:Debug("PARSING glSpellsCSVNames",glMsgType.INIT_BASE) local spellsCSVColumnsNames=explode_internal(glSpellsCSVNames) Logger:Debug("PARSING glSpellsCSVData",glMsgType.INIT_BASE) glCSVSpellsCardsByOrder=explode_internal(glSpellsCSVData,spellsCSVColumnsNames) glCSVSpellsCardsByID={} local n=i local i=1 foreach(glCSVSpellsCardsByOrder,function(temp) if not temp.id then return end if not temp.turnedOff then if temp.tags~=nil then temp.tags=string.split(temp.tags,",") end local tags={} foreach(temp.tags,function(tagName) local tagEntry=nil local eff=glSpellsTags[tagName] if eff then tagEntry=deepcopy(eff) else if string.find(tagName,"_") then local split=string.split(tagName,"_") Logger:Trace("found spell tag with split:"..tagName,glMsgType.INIT_BASE) if glSpellsTags[split[1]] then tagEntry=deepcopy(glSpellsTags[split[1]]) tagEntry.data=deepcopy(tagEntry.data) tagEntry.data.split=split Logger:Trace("added spell tag:"..tagName,glMsgType.INIT_BASE) else tagEntry=deepcopy(glSpellsTags.DEFAULT) Logger:Error("NOT added spell tag:"..tagName,glMsgType.INIT_BASE) end if tagEntry.funcOnCreatingThisTagOnUnit then tagEntry:funcOnCreatingThisTagOnUnit(nil) end else tagEntry=deepcopy(glSpellsTags.DEFAULT) end end if tagEntry then table.insert(tags,tagEntry) end end) temp.tags=tags if #tags>0 then if temp.id~="S034" then glCSVSpellsCardsByID[temp.id]=temp local card=CardClass(temp.id,temp.name,temp.sprite,temp.tags,temp.rarity,temp.desc,gh:InitSpellCardStatsTable(temp.manaCost,temp.spellPower),true) gh.allCards[temp.id]=card end end i=i+1 else Logger:Debug("NOT PROCESSING SPELL:"..temp.id, glMsgType.INIT_BASE) end end) local fatique=gh.allCards["A002"]:DeepCopy() fatique.id="EMPTY" fatique.isFatiqueCard=true gh.allCards.FATIQUE=fatique local tutorialCard=deepcopy(gh.allCards["A008"]) tutorialCard.stats.manaCost.cur=3 tutorialCard.id="T000" tutorialCard.isTutorialCard=true table.insert(tutorialCard.tags,deepcopy(glUnitTags.DASH)) gh.allCards.TUTORIAL1=tutorialCard tutorialCard=deepcopy(gh.allCards["U007"]) tutorialCard.stats.manaCost.cur=2 tutorialCard.id="T001" tutorialCard.isTutorialCard=true gh.allCards.TUTORIAL2=tutorialCard tutorialCard=deepcopy(gh.allCards["H004"]) tutorialCard.stats.manaCost.cur=2 tutorialCard.stats.hp.max=5 tutorialCard.stats.hp.cur=5 tutorialCard.id="H004" tutorialCard.isTutorialCard=true gh.allCards.TUTORIAL4=tutorialCard tutorialCard=deepcopy(gh.allCards["S012"]) tutorialCard.stats.spellPower.max=12 tutorialCard.stats.spellPower:setToMax() tutorialCard.tags={} table.insert(tutorialCard.tags,deepcopy(glSpellsTags.ARMORBUFF_TUTORIAL)) tutorialCard.id="T002" tutorialCard.isTutorialCard=true gh.allCards.TUTORIAL3=tutorialCard n=n+i+1 Logger:Debug("Number of cards in game:"..n,glMsgType.INIT_BASE) Logger:Debug("PARSING glDecksCSVNames",glMsgType.INIT_BASE) local decksCSVColumnsNames=explode_internal(glDecksCSVNames) Logger:Debug("PARSING glDecksCSVData",glMsgType.INIT_BASE) glCSVDecksDefinitionsByOrder=explode_internal(glDecksCSVData,decksCSVColumnsNames) glCSVDecksDefinitionsByID={} n=0 glEnemyDecks={} foreach(glCSVDecksDefinitionsByOrder,function(temp) if not temp.id then return end if not temp.turnedOff then local deck={} if temp.keyCards then temp.keyCards=string.split(temp.keyCards,",") local supportCardsDef={} if temp.supportingCards then for word in string.gmatch(temp.supportingCards,"[A-Z][0-9][0-9][0-9],[0-9],[0-9]") do table.insert(supportCardsDef,word) end end temp.supportingCards={} foreach(supportCardsDef,function(str) local split=string.split(str,",") table.insert(temp.supportingCards,{id=split[1],min=split[2],max=split[3]}) end) if temp.playerDeck~=1 then table.insert(glEnemyDecks,temp.id) end glCSVDecksDefinitionsByID[temp.id]=temp deck=gh:GenerateVariationOfTheDeck(temp.id,temp.startingSize) gh.allDeckTemplates[temp.id]=deck end n=n+1 else Logger:Debug("NOT PROCESSING DECK:"..temp.id, glMsgType.INIT_BASE) end end) Logger:Debug("number of premade decks:"..n,glMsgType.INIT_BASE) --preinitialize ai deck gh.enemyChoosenDeckID="DECK001" glEnemyDecksByLevel={{"DECK003","DECK004","DECK005"},{"DECK006","DECK007","DECK008","DECK009"},{"DECK010","DECK011","DECK012"},{"DECK000","DECK001","DECK002"},{"DECK025","DECK026","DECK027"}} glDungeonRunDeckList={} Logger:Debug("PARSING glLeadersCSVNames",glMsgType.INIT_BASE) local leadersCSVColumnsNames=explode_internal(glLeadersCSVNames) Logger:Debug("PARSING glLeadersCSVData",glMsgType.INIT_BASE) glCSVLeadersCardsByOrder=explode_internal(glLeadersCSVData,leadersCSVColumnsNames) glCSVLeadersCardsByID={} n=0 glEnemyLeadersByLevel={{},{},{},{}} foreach(glCSVLeadersCardsByOrder,function(temp) if not temp.id then return end if not temp.turnedOff then if temp.tags~=nil then temp.tags=string.split(temp.tags,",") else temp.tags={} end local splitTags=temp.tags temp.tags={} foreach(splitTags,function(tagName) local tagEntry=nil if glUnitTags[tagName] then tagEntry=deepcopy(glUnitTags[tagName]) else if string.find(tagName,"_") then local split=string.split(tagName,"_") Logger:Trace("unit tag with split:"..tagName,glMsgType.INIT_BASE) if glUnitTags[split[1]] then tagEntry=deepcopy(glUnitTags[split[1]]) tagEntry.data=deepcopy(tagEntry.data) tagEntry.data.split=split tagEntry.data.spellPWR=1 end else tagEntry=deepcopy(glUnitTags.DEFAULT) end end table.insert(temp.tags,tagEntry) end) temp.supportingCards={} foreach(supportCardsDef,function(str) local split=string.split(str,",") end) if temp.dungeonGenerationInfo then for word in string.gmatch(temp.dungeonSubLevelUpgade,"[0-9],[0-9],[0-9]") do local split=string.split(word,",") temp.upgradePerSubLvl={atk=split[1],hp=split[2],armor=split[3]} end for word in string.gmatch(temp.dungeonGenerationInfo,"[0-9],[A-Z][A-Z][A-Z][A-Z][0-9][0-9][0-9]") do local split=string.split(word,",") temp.deckID=split[2] local i=tonumber(split[1]) local t=glEnemyLeadersByLevel[i] table.insert(t,temp) glEnemyLeadersByLevel[i]=t end end glCSVLeadersCardsByID[temp.id]=temp local card=LeaderClass(temp.id,temp.id,temp.sprite,temp.tags,temp.rarity,temp.desc,gh:InitUnitCardStatsTable(temp.hp,temp.armor,temp.attack,temp.manaCost),temp.unitBasedOn) gh.allCards[temp.id]=card n=n+1 else Logger:Debug("NOT PROCESSING LEADER:"..temp.id, glMsgType.INIT_BASE) end end) Logger:Debug("Number of leaders in game:"..n,glMsgType.INIT_BASE) local temp=gh.allCards["L001"] local leader1=temp:DeepCopy() leader1.isPlayerCard=true leader1.sprite=392 temp=gh.allCards["L001"] local leader2=temp:DeepCopy() leader1.cardGUI=GUIHelper.playerLeaderCard leader2.cardGUI=GUIHelper.enemyLeaderCard gh.playerLeaderCard=leader1 GameHelper:LoadAvatarFromPMEM() gh.playerLeaderFormula=leader1:DeepCopy() gh.enemyLeaderCard=leader2 gh.currentTurnLeader=gh.playerLeaderCard gh:LoadOptionsFromPMEM() gh:LoadMoreOptionsFromPMEM() end function InitThingsRequiringGameSeed() InitCardBuckets() end function InitCardBuckets() local gh=GameHelper foreach(glCardBuckets,function(bucket) local allCards={} local lowCostCards={} local mediumCostCards={} local highCostCards={} local buckets={} local lowBuckets={} local highBuckets={} foreach(gh.allCards,function(card) local found=false if string.sub(card.id,1,1)=="T" or card.id=="EMPTY" or card.isFatiqueCard or card.isTutorialCard then return end local legendaryCard=string.sub(card.rarity,1,1)=="L" if legendaryCard then if bucket.name=="LEGENDARY" then found=string.sub(bucket.name,1,1)==string.sub(card.rarity,1,1) end elseif bucket.name=="ANIMAL" or bucket.name=="UNDEAD" or bucket.name=="HUMAN" then found=string.sub(bucket.name,1,1)==string.sub(card.id,1,1) elseif bucket.name=="RARE" then found=string.sub(bucket.name,1,1)==string.sub(card.rarity,1,1) elseif bucket.name=="SPELLS" then found=card.isSpell elseif bucket.name=="VERY_SOMETHING" then found=string.find(card.name,"VERY") else if card.stats.manaCost.cur then if bucket.name=="SMALL" then found=card.stats.manaCost.cur<=3 elseif bucket.name=="MEDIUM" then found=card.stats.manaCost.cur>3 and card.stats.manaCost.cur<=6 elseif bucket.name=="LARGE" then found=card.stats.manaCost.cur>6 end end foreach(card.tags,function(tag) found=found or tag.name==bucket.name end) end if found then if card.stats.manaCost.cur then table.insert(allCards,card.id) if card.stats.manaCost.cur<3 then table.insert(lowCostCards,card.id) end if card.stats.manaCost.cur>1 and card.stats.manaCost.cur<5 then table.insert(mediumCostCards,card.id) end if card.stats.manaCost.cur>3 then table.insert(highCostCards,card.id) end end end end) local lCC=deepcopy(lowCostCards) local mCC=deepcopy(mediumCostCards) local hCC=deepcopy(highCostCards) if bucket.name=="SMALL" then hCC=deepcopy(lCC) elseif bucket.name=="MEDIUM" then lCC=deepcopy(mCC) elseif bucket.name=="LARGE" then lCC=deepcopy(hCC) mCC=deepcopy(hCC) end if bucket.name=="SMALL" or bucket.name=="LARGE" or bucket.name=="MEDIUM" then Logger:Trace(bucket.name..";"..(#lCC)..","..(#mCC)..";"..(#hCC),glMsgType.INIT_BASE) end if #lCC>0 and #mCC>0 and #hCC>0 then local lastLowCard,lastMedCard,lastHighCard while((#lCC)>0 and (#mCC)>0 and (#hCC)>0) do local lowCard=table.remove(lCC,math.random(#lCC)) local medCard=table.remove(mCC,math.random(#mCC)) local highCard=table.remove(hCC,math.random(#hCC)) local crds={lowCard,medCard,highCard} local canCont=true foreach(crds,function(card) if card.isFatiqueCard or card.isTutorialCard then canCont=false end end) if canCont then if medCard then if lowCard then if highCard then table.insert(buckets,{lowCard,medCard,highCard}) end table.insert(lowBuckets,{lowCard,maybe() and lastLowCard or lastMedCard,medCard}) lastLowCard=lowCard end lastMedCard=medCard if highCard then table.insert(highBuckets,{medCard,maybe() and lastHighCard or lastMedCard,highCard}) lastHighCard=highCard end end end end end bucket.allCards=allCards bucket.lowCostCards=lowCostCards bucket.mediumCostCards=mediumCostCards bucket.highCostCards=highCostCards bucket.buckets=buckets bucket.lowCostBuckets=lowBuckets bucket.highCostBuckets=highBuckets end) end function InitBaseGUI() glTutorialIsBlockingGUI=false glEmptyGUIStyle=ticuare.Style({ }) glBackgroundBlackGUIStyle=ticuare.Style({ colors = {0,0,0}, }) glBackgroundStaticVioletGUIStyle=ticuare.Style({ colors = {1,1,1}, }) glBackgroundHoverableVioletGUIStyle=ticuare.Style({ colors = {0,1,2}, }) glTutorialDialogGUIStyle=ticuare.Style({ colors = {1,1,1}, border = { colors = {9,14,15}, width = 1, }, }) glBackgroundWithBorderGUIBlackStyle=ticuare.Style({ colors = {0,0,0}, border = { colors = {1,1,1}, width = 1, }, }) glBackgroundWithBorderClickableGUIStyle=ticuare.Style({ colors = {0,2,1}, border = { colors = {1,2,14}, width = 1, }, }) glBackgroundWithBorderClickableGUIStyleClicked=ticuare.Style({ colors = {1,2,2}, border = { colors = {11,2,14}, width = 1, }, }) glBackgroundWithBorderClickable2GUIStyle=ticuare.Style({ colors = {0,1,2}, border = { colors = {2,8,13}, width = 1, }, }) glGUIFrameStyleActiveRedButton = ticuare.Style({ colors = {5,11,15}, border = { colors = {6,9,9}, width = 1, }, }) glGUIFrameStyleUnusableCard = ticuare.Style({ colors = {1,4,2}, border = { colors = {3,2,2}, width = 1, }, }) glGUIFrameStyleTotallyUnusableCard = ticuare.Style({ colors = {1,4,2}, border = { colors = {0,0,0}, width = 1, }, }) glGUIFrameStyleActiveOKCard = ticuare.Style({ colors = {1,4,2}, border = { colors = {11,5,8}, width = 1, }, }) glGUIFrameStyleBlinkCard1 = ticuare.Style({ colors = {1,4,2}, border = { colors = {14,5,8}, width = 1, }, }) glGUIFrameStyleBlinkCard2 = ticuare.Style({ colors = {1,4,2}, border = { colors = {9,5,8}, width = 1, }, }) glGUIFrameStyleActiveWarningCard = ticuare.Style({ colors = {1,4,2}, border = { colors = {14,9,2}, width = 1, }, }) --game options screen GUICreator:CreateGameOptionsScreen() --MOUSE glGUIFrameMouseTooltip = GUIHelper:CreateGUIFrame("glGUIFrameMouseTooltip",10,10,80,50) glGUIFrameMouseTooltip.colors = {0,0,0} glGUIFrameMouseTooltip.border = { colors = {3,3,3}, width = 1, } glGUIFrameMouseTooltip.textArray={} --hack: so tooltip can be below mouse cursor when tooltip is too big to be anywhere else glGUIFrameMouseTooltip.updateSelf=function() end end function InitGameGUI() GUIHelper.AIActionFramesList={} glFullScreenGameBackground= GUIHelper:CreateGUIFrame("glFullScreenGameBackground",0,0,glScreenPixelWidth,glScreenPixelHeight,glBackgroundBlackGUIStyle) glFullScreenGameBackground.onPress=function() if GameHelper.controlScheme==2 then GUIHelper.controlHoveredOver=nil end end glFullScreenGameBackground:Content(function(ref,x,y) local s1=(GameHelper.finishingMatch and (GameHelper.playerWon and "PLAYER WON!" or "PLAYER LOST") or (GameHelper.isPlayerTurn and "PLAYER TURN" or "ENEMY TURN")) local l = print(s1,-200,96,5,false,(GameHelper.finishingMatch and 2 or 1)) print(s1,x+ref.w/2-l/2,y+48,(GameHelper.finishingMatch and ((GameHelper.playerWon) and (glFrame60FramesCounter%30<15 and 14 or 5) or (glFrame60FramesCounter%30<15 and 6 or 57)) or 5),false,(GameHelper.finishingMatch and 2 or 1)) if (not GameHelper.finishingMatch) then local s2=AIHelper.aiCurrentMoveDesc if not GameHelper.isPlayerTurn then s2=math.round(AIHelper.aiTurnTimeCur,1) end l = print(s2,-200,100,5) print(s2,x+ref.w/2-l/2+1,y+55,(GameHelper.isPlayerTurn and 15 or 11)) end end) -- init battlefield GUICreator:CreateBattlefieldScreen() -- redraw starting cards gui GUICreator:CreateRedrawingStartingCardsScreen() --to draw stuff for tutorials/action queues/anything that needs to not be obscured by game glFullScreenGameOverlayToDrawOn= GUIHelper:CreateGUIFrame("glFullScreenGameOverlayToDrawOn",0,0,glScreenPixelWidth,glScreenPixelHeight,nil) glFullScreenGameOverlayToDrawOn.updateSelf=function() end glFullScreenGameOverlayToDrawOn:Content(function(ref,x,y) foreach(ref.pointCoordsAndColorToDrawLinesList,function(coords) if coords then local half=math.round(coords.w/2) for i=0,coords.w do line(coords.x1+i-half,coords.y1,coords.x2+i-half,coords.y2,coords.c) end end end) ref.pointCoordsAndColorToDrawLinesList={} end) glFullScreenGameOverlayToDrawOn.pointCoordsAndColorToDrawLinesList={} GUICreator:CreateChooseDeckScreen() GUICreator:CreateLeaderCreationScreen() glCreateLeaderCardGUI:hide() --find card tag gui GUICreator:CreateFindTagDialog() glFindCardTagGUI:hide() --choose artifact local frameContentFunc=function(ref,x,y) print("ADD ARTIFACT TO YOUR DECK ",x+1,y+1,5,false,1,false) end local okClickFunc=function(ref) if glChooseartifactGUI.playerChoosenartifactID then GUIHelper.InteractableActiveControlBaseClickFunc(ref) GameHelper.finishedChoosingArtifact=true GameHelper.playerChoosenartifactID=glChooseartifactGUI.playerChoosenartifactID glChooseartifactGUI:resetGUIFunc() glChooseartifactGUI.playerChoosenartifactID=nil GameHelper.skipCardBuckets=true GameHelper.finishedChoosingCardBucket=true end end GameHelper.artifactOption1=glLeaderArtifacts["DOUBLE_ATK"] GameHelper.artifactOption2=glLeaderArtifacts["DOUBLE_HP"] GameHelper.artifactOption3=glLeaderArtifacts["DOUBLE_ARMOR"] local option1ContentFunc=function(ref,x,y) print(GameHelper.artifactOption1.name,x+1,y+1,(((not glChooseartifactGUI.playerChoosenartifactID) or (glChooseartifactGUI.playerChoosenartifactID and GameHelper.artifactOption1.name==glLeaderArtifacts[glChooseartifactGUI.playerChoosenartifactID].name)) and 6 or 1),false,1,string.len(GameHelper.artifactOption1.name)>13) end local option1ClickFunc= function(ref) ref:basicOptionClickFunc() glChooseartifactGUI.playerChoosenartifactID=GameHelper.artifactOption1.id end local option1TextStr=GameHelper.artifactOption1.desc[1].str local option2ContentFunc=function(ref,x,y) print(GameHelper.artifactOption2.name,x+1,y+1,(((not glChooseartifactGUI.playerChoosenartifactID) or (glChooseartifactGUI.playerChoosenartifactID and GameHelper.artifactOption2.name==glLeaderArtifacts[glChooseartifactGUI.playerChoosenartifactID].name)) and 6 or 1),false,1,string.len(GameHelper.artifactOption2.name)>13) end local option2ClickFunc= function(ref) ref:basicOptionClickFunc() glChooseartifactGUI.playerChoosenartifactID=GameHelper.artifactOption2.id end local option2TextStr=GameHelper.artifactOption2.desc[1].str local option3ContentFunc=function(ref,x,y) print(GameHelper.artifactOption3.name,x+1,y+1,(((not glChooseartifactGUI.playerChoosenartifactID) or (glChooseartifactGUI.playerChoosenartifactID and GameHelper.artifactOption3.name==glLeaderArtifacts[glChooseartifactGUI.playerChoosenartifactID].name)) and 6 or 1),false,1,string.len(GameHelper.artifactOption3.name)>13) end local option3ClickFunc= function(ref) ref:basicOptionClickFunc() glChooseartifactGUI.playerChoosenartifactID=GameHelper.artifactOption3.id end local option3TextStr=GameHelper.artifactOption3.desc[1].str glChooseartifactGUI=GUIHelper:CreateGUIDialogWithXChoices("glChooseartifactGUI",0,0,glScreenPixelWidth,glScreenPixelHeight,glBackgroundWithBorderGUIBlackStyle,frameContentFunc,okClickFunc,3,1, {{optionContentFunc=option1ContentFunc,optionClickFunc=option1ClickFunc,optionTextStr=option1TextStr}, {optionContentFunc=option2ContentFunc,optionClickFunc=option2ClickFunc,optionTextStr=option2TextStr}, {optionContentFunc=option3ContentFunc,optionClickFunc=option3ClickFunc,optionTextStr=option3TextStr}}) glChooseartifactGUI:hide() GUICreator:CreateChooseBucketsScreen() glChooseBucketsGUI:hide() --//TODO: choose tag reward screen --choose legendary card screen GUICreator:CreateChooseLegendaryCardScreen() --inventory screen GUICreator:CreateInventoryScreen() gllnventoryScreenFrameGUI:hide() --RUN PROGRESS SCREEN glRunProgressFrameGUI=GUIHelper:CreateGUIFrame("glRunProgressFrameGUI",0,0,glScreenPixelWidth,glScreenPixelHeight,glBackgroundWithBorderGUIBlackStyle) glRunProgressFrameGUI:Content(function(ref,x,y) local offN=GameHelper.gamesWon print("RUN PROGRESS: "..offN.."/"..#glDungeonRunDeckList,x+1,y+1,5) y=y+ref.h-80 local drawPlayerFunc=function(ref,x,w) spr(GameHelper.playerLeaderCard.sprite,x,y,-1,1,0,0,2,2) line(x+8,y+2,x+8,y-4,11) --player run line print("YOU",x+1,y-12,11) local offX=0 if GameHelper.maxPlayerLives==1 then offX=-5 elseif GameHelper.maxPlayerLives>2 then offX=(GameHelper.maxPlayerLives-2)*5 end for i=1,GameHelper.maxPlayerLives do spr(GameHelper.currentPlayerLives>=i and 257 or 276,x-offX+(i-1)*10,y-21) end end local drawEnemyFunc=function(ref,x,w,enemyLeader,i,n,offX,offN) if enemyLeader then local beaten=i0 and i==0 then x=x+7 end print(isBoss and "BOSS" or "ENEMY",x-(isBoss and 2 or 5),y-30,enemyC) if beaten then line(x-6+(isBoss and -2 or 0),y-28,x+23,y-28,15) --strikeout spr(272,x+(isBoss and -2 or 0)+6,y-46) --skull end print(enemyLeader.id,x-2,y-37,1) end end local offX=38 line(x+11+offN*offX-(makeThisEventOnRight and 40 or 0),y+12,x+ref.w-14,y+12,15) --progress run line local thisEvent=(offN-i)==1 local shownEventStuff=GameHelper.showedRunProgressBeforeEvent local makeThisEventOnRight=not shownEventStuff and (offN>0) if makeThisEventOnRight then x=x-20 end drawPlayerFunc(ref,x+3+offN*offX+offN*2,y) if makeThisEventOnRight then x=x+20 end local n=(#glDungeonRunEnemyLeaderList) for i=0,n do local x1=x+offX*i+2*i+(i>=offN and 23 or 0) local enemyLeader=glDungeonRunEnemyLeaderList[i+1] local isBoss=i==(n-1) drawEnemyFunc(ref,x1,y,enemyLeader,i,n,offX,offN) local enemyBorder=glRunProgressFrameGUI.enemyBordersGUI[i+1] enemyBorder.x=x1-1+(isBoss and -2 or 0) enemyBorder.y=(isBoss and y+12 or y)-1 enemyBorder.card=enemyLeader enemyBorder.cardObj=enemyLeader end end) local createEnemyBorderControl=function(parent,x,y,i) local hoverFunc= function(ref) if GameHelper.controlScheme<2 then GUIHelper.controlHoveredOver=ref GameHelper.cardGUIElemHoveredOver=ref end end local pressFunc= function(ref) if GameHelper.controlScheme==2 then GUIHelper.controlHoveredOver=ref GameHelper.cardGUIElemHoveredOver=ref end end local releaseFunc=function(r) if GameHelper.controlScheme==2 then GUIHelper.controlHoveredOver=nil GameHelper.cardGUIElemHoveredOver=nil end end local cardGUI=GUIHelper:CreateGUIFrame("createEnemyBorderControl_"..i,x-1,y-1,18,18,glGUIFrameStyleUnusableCard) cardGUI:addParent(parent) cardGUI:Content(GUIHelper.BucketCardDrawingFunction) cardGUI.onHover=hoverFunc cardGUI.onPress=pressFunc cardGUI.onRelease=releaseFunc cardGUI.onCleanRelease=releaseFunc cardGUI.basicOptionClickFunc=GUIHelper.basicOptionClickFunc return cardGUI end local x=glRunProgressFrameGUI.x local offX=38 local y=glRunProgressFrameGUI.y glRunProgressFrameGUI.enemyBordersGUI={} local n=6 for i=0,n do local x1=x+offX*i+2*i local isBoss=i==(n-1) table.insert(glRunProgressFrameGUI.enemyBordersGUI,createEnemyBorderControl(glRunProgressFrameGUI,x1-(isBoss and 2 or 0),(isBoss and y+12 or y),i)) end glRunProgressFrameOKGUI=GUIHelper:CreateButtonWidget("glRunProgressFrameOKGUI",glRunProgressFrameGUI:getCenterX()-20,glRunProgressFrameGUI.y+glRunProgressFrameGUI.h-11,40,9,glBackgroundWithBorderClickableGUIStyle,frame,"OK") glRunProgressFrameOKGUI:addParent(glRunProgressFrameGUI) glRunProgressFrameOKGUI.onCleanRelease=function(ref) if GameHelper.finishedChoosingArtifact or GameHelper.isfirstBattle then GameHelper:InitMatchStart() end GameHelper.showedRunProgressBeforeEvent=true glRunProgressFrameGUI:hide() GUIHelper.InteractableActiveControlBaseClickFunc(ref) GameHelper.ShowedInventoryScreen=false GameHelper.ShowingInventoryScreen=false end local empty={} glRunProgressFrameGUI:hide() --LET PLAYER CHOOSE EVENT BECAUSE OF LOSING SCREEN GUICreator:CreatePlayerWakingUpAfterLoseEventScreen() glChooseEventOnDeathGUI:hide() --GET LEADER CARD TO DECK SCREEN GUICreator:CreateAddEnemyToDeckScreen() glAddLeaderCardToDeckGUI:hide() --END SCREEN GUICreator:CreateGameEndScreen() glGUIFrameEndScreenBackground:hide() glGUIFrameMouseCardPreview=GUIHelper:CreateGUIFrame("glGUIFrameMouseCardPreview",-200,0,41,73) glGUIFrameMouseCardPreview.origW=glGUIFrameMouseCardPreview.w glGUIFrameMouseCardPreview.origH=glGUIFrameMouseCardPreview.h glGUIFrameMouseCardPreview:style(glGUIFrameStyleUnusableCard) glGUIFrameMouseCardPreview:Content(GUIHelper.HandCardDrawingFunction) glGUIFrameMouseCardPreview.updateSelf=function() local cardObj=glGUIFrameMouseCardPreview.cardObj if cardObj then glGUIFrameMouseCardPreview.h=((cardObj.isLeaderCard and #cardObj.tags>3) and (glGUIFrameMouseCardPreview.origH+16*math.min(3,(#cardObj.tags-3))) or glGUIFrameMouseCardPreview.origH) end end glGUIFrameMouseCard2ndPreview = GUIHelper:CreateGUIFrame("glGUIFrameMouseCard2ndPreview",-200,0,41,73) glGUIFrameMouseCard2ndPreview.origW=glGUIFrameMouseCardPreview.w glGUIFrameMouseCard2ndPreview.origH=glGUIFrameMouseCardPreview.h glGUIFrameMouseCard2ndPreview:style(glGUIFrameStyleUnusableCard) glGUIFrameMouseCard2ndPreview:Content(GUIHelper.HandCardDrawingFunction) glGUIFrameMouseCard2ndPreview.updateSelf=function() local cardObj=glGUIFrameMouseCard2ndPreview.cardObj if cardObj then glGUIFrameMouseCard2ndPreview.h=((cardObj.isLeaderCard and #cardObj.tags>3) and (glGUIFrameMouseCard2ndPreview.origH+16*math.min(3,(#cardObj.tags-3))) or glGUIFrameMouseCard2ndPreview.origH) end end GUICreator:CreateSelectLeaderTagScreen() --remove not needed screens GUICreator:RemoveFindTagDialog() GUICreator:RemoveRedrawingStartingCardsScreen() GUICreator:RemoveChooseLegendaryCardScreen() GUICreator:RemovePlayerWakingUpAfterLoseEventScreen() GUICreator:RemoveGameEndScreen() GUICreator:RemoveSelectLeaderTagScreen() end function InitGameLogic() --INIT GAME GameHelper:GenerateDungeonRun(2,2,1) gameInitialized=true end function UpdateBase(deltaTime) BaseUpdate:UpdateBaseVars() Logger:Update(deltaTime) AsyncQueueLogicHelper:Update(deltaTime) BaseUpdate:GameTurnGUIClear() --UPDATE TICUARE GUI FOR THIS FRAME (gets events etc.) ticuare.update(glMouse.x,glMouse.y,glMouse.lPressed) local up,down,left,right,a,b,x,y=btnp(0),btnp(1),btnp(2),btnp(3),btnp(4),btnp(5),btnp(6),btnp(7) local clickedAnyKey=up or down or left or right or a or b or x or y BaseUpdate:SetMouseGlobalVars(up,down,left,right,a,b,x,y) local mx,my,lmd,mmd,rmd=mouse() BaseUpdate:SetTypeOfControls(clickedAnyKey) BaseUpdate:UpdateControlsForThisFrame(mx,my,lmd,mmd,rmd) if GUIScenarioQueueSystem:CanUpdate() then for i = 1, GUIScenarioQueueSystem.availPointsForFrame, 1 do GUIScenarioQueueSystem:ProcessOnce(deltaTime) end end GUIScenarioQueueSystem:EndOfProcessing() end function UpdateGame(deltaTime) StateHelper.lastHooveredCard=GameHelper.cardGUIElemHoveredOver StateHelper.lastHooveredControl=GUIHelper.controlHoveredOver UpdateBase(deltaTime) local mx=glMouse.x local my=glMouse.y local lmd=glMouse.lPressed if glMouse.rPressed then StateHelper.CleanPlayerMouseSelection() end if glTutorialIsBlockingGUI and glTutorialDialog and glTutorialDialog:isShown() then --hovered card can block ok button on tutorial local i=0 foreach(GUIHelper.playerHandCards,function(cardGUI) local cardObj=cardGUI.cardObj local hadCardObj=cardGUI.cardObj and (cardObj and cardObj.cardGUI or false) if cardObj then cardGUI.cardObj=cardObj cardObj.cardGUI=cardGUI if i%2==1 then cardGUI:toFront(ticuare.hz) else cardGUI:toFront(ticuare.hz-1) end cardGUI.x=cardGUI.origX cardGUI.y=glScreenPixelHeight-22+(i%2==1 and 1 or -5) end i=i+1 end) return end StateHelper.gameStarted=GameHelper.playerChoosenCards StateHelper.gameModeStarted=GameHelper.playerChoosenDeck --game logic if GUIHelper.gameOptionsButtonClicked then StateHelper:OpenOptionWindowAndUnclick() return end if GUIHelper.gameOptionsOpened then return end if GUIHelper.endTurnButtonClicked then GameHelper:EndTurn() end UpdateGameEveryOtherTurn(deltaTime) UpdateMouse() end function UpdateGameEveryOtherTurn(deltaTime) local selCardGUI1st=GameHelper.cardGUIElemSelected1st local cardObj1st=selCardGUI1st and selCardGUI1st.cardObj or nil local statsCard1st=cardObj1st and cardObj1st.stats or nil StateHelper.selCardGUI2nd=GameHelper.cardGUIElemSelected StateHelper.cardObj2nd=StateHelper.selCardGUI2nd and StateHelper.selCardGUI2nd.cardObj or nil local statsCard2nd=StateHelper.cardObj2nd and StateHelper.cardObj2nd.stats or nil if StateHelper.gameStarted then StateHelper:UpdatePlayingState(deltaTime,selCardGUI1st,cardObj1st,statsCard1st,StateHelper.selCardGUI2nd,StateHelper.cardObj2nd,statsCard2nd) else StateHelper:UpdateNonPlayingState(deltaTime,selCardGUI1st,cardObj1st,statsCard1st,StateHelper.selCardGUI2nd,StateHelper.cardObj2nd,statsCard2nd) end GameHelper.haveStuffToDo=GameHelper.haveStuffToDo and GameHelper.haveStuffToDo or GameHelper.playerLeaderCard.stats.attacksAvail.cur>0 --UPDATING GUI StateHelper:PassTimeOfMouseHoveringOnCard(deltaTime) StateHelper.cardHoveredGUI=GameHelper.cardGUIElemHoveredOver StateHelper.cardGUI1st=GameHelper.cardGUIElemSelected1st StateHelper:ProcessBattlefieldGUI() StateHelper:ProcessTooltipsAndCardHoverGUI() glEndTurnButton.border=(GameHelper.isPlayerTurn and glGUIFrameStyleActiveOKCard.border or glGUIFrameStyleUnusableCard.border) end function UpdateMouse() local mouseControls={glGUIFrameMouseTooltip,glGUIFrameMouseCardPreview,glGUIFrameMouseCard2ndPreview} --if GameHelper.controlScheme==1 then local cardPreviewSetCoords=glGUIFrameMouseCardPreview.setMouseCoords if cardPreviewSetCoords and ((GameHelper.cardGUIHoveredTime>GameHelper.delayBeforeShowingFullCard)) then --set position once so player can hover over tooltip card tags and learn about them glGUIFrameMouseCardPreview.x=glMouse.x+2 glGUIFrameMouseCardPreview.y=glMouse.y+2 glGUIFrameMouseCardPreview.setMouseCoords=false end local showCard=GameHelper.showFullCardPreviewInBattle>0 or (GameHelper.ShowingInventoryScreen) glGUIFrameMouseCardPreview:visible(showCard and glGUIFrameMouseCardPreview.cardObj~=nil) if GUIHelper.controlHoveredOver and GUIHelper.controlHoveredOver.tooltipTexts and GUIHelper.controlHoveredTime>=GameHelper.delayBeforeShowingTooltips then table.insert(glGUIFrameMouseTooltip.textArray,{text=GUIHelper.controlHoveredOver.controlName,color=14,smallFont=false}) foreach(GUIHelper.controlHoveredOver.tooltipTexts,function(line) table.insert(glGUIFrameMouseTooltip.textArray,{text=line.text,color=line.c,smallFont=true}) end) end --set above the mouse as a start glGUIFrameMouseTooltip.x=glMouse.x+2 glGUIFrameMouseTooltip.y=glMouse.y-2-glGUIFrameMouseTooltip.h if cardPreviewSetCoords and #glGUIFrameMouseTooltip.textArray>0 then glGUIFrameMouseTooltip.x=(glGUIFrameMouseCardPreview.x+glGUIFrameMouseCardPreview.w+1) glGUIFrameMouseTooltip.y=glGUIFrameMouseCardPreview.y-glGUIFrameMouseTooltip.h end glGUIFrameMouseTooltip:visible(#glGUIFrameMouseTooltip.textArray>0) glGUIFrameMouseTooltip:Content(GUIHelper.TextLogContentFunction) if glGUIFrameMouseCard2ndPreview.setMouseCoords and ((GameHelper.cardGUIHoveredTime>GameHelper.delayBeforeShowingFullCard)) then --set position once so player can hover over tooltip card tags and learn about them glGUIFrameMouseCard2ndPreview.x=glGUIFrameMouseTooltip.x+2 glGUIFrameMouseCard2ndPreview.y=glGUIFrameMouseTooltip.y+2 glGUIFrameMouseCard2ndPreview.setMouseCoords=true end glGUIFrameMouseCard2ndPreview:visible(glGUIFrameMouseCard2ndPreview.cardObj~=nil) foreach(mouseControls,function(ctrl) local i=0 while (ctrl.x+ctrl.w)>(glScreenPixelWidth) do ctrl.x=ctrl.x-1 end while ctrl.x<0 do ctrl.x=ctrl.x+1 end while (ctrl.y+ctrl.h)>(glScreenPixelHeight) do ctrl.y=ctrl.y-1 end while ctrl.y<0 do ctrl.y=ctrl.y+1 end local oldY=ctrl.y while ctrl.xglMouse.x and (ctrl.y+ctrl.h)>glMouse.y do ctrl.y=ctrl.y-1 end if ctrl.y<0 then ctrl.y=oldY end ctrl:toFront(ticuare.hz+1) end) if not showCard then glGUIFrameMouseCardPreview.x=-1000 end end function DrawBeforeGUI() end function DrawAfterGUI() local deltaTime=glFrameTimePerFrame local cardGUI1st=GameHelper.cardGUIElemSelected1st if gameInitialized then if cardGUI1st and cardGUI1st.isPlayerCard and cardGUI1st.cardObj then local c=GUIHelper.lineHelperColor and GUIHelper.lineHelperColor or 15 if GameHelper.controlScheme<2 then line(cardGUI1st:getCenterX()-1,cardGUI1st.y,glMouse.x-1,glMouse.y,c) line(cardGUI1st:getCenterX(),cardGUI1st.y,glMouse.x,glMouse.y,c) line(cardGUI1st:getCenterX()+1,cardGUI1st.y,glMouse.x+1,glMouse.y,c) end end AsyncQueueDrawHelper:Update(deltaTime) glGUIFrameMouseTooltip:drawSelf() end local str="SLEEPLESS CARDS\nPROGRESS UPDATE #12" local x=71 local y=20 end function Draw() cls() end -- EventHelper CLASS EventHelper = {} EventHelper.__index=EventHelper EventHelper.id="EventHelper" EventHelper.listenerID=0 EventHelper.showDebug=true EventHelper.eventListenersDict={} function EventHelper:Init() end ---@param eventID glEventTypes ---@param listenerObj any ---@param listenerFunc function function EventHelper:RegisterListenerToEvent(eventID,listenerObj,listenerFunc) local listenerID=(listenerObj and listenerObj.id or self.listenerID) if not listenerObj then self.listenerID=self.listenerID+1 end if self.showDebug then Logger:Trace("Registering for event:"..eventID..";listener:"..listenerID,glMsgType.EVENT) end if not self.eventListenersDict[eventID] then if self.showDebug then Logger:Trace(" Creating new array",glMsgType.EVENT) end self.eventListenersDict[eventID]={} else if self.showDebug then Logger:Trace(" Adding new listener",glMsgType.EVENT) end end local callList=self.eventListenersDict[eventID] callList[listenerID]={func=listenerFunc,obj=listenerObj} end ---@param eventID glEventTypes ---@param callerObj any ---@param simulateOnly boolean ---@param valuesArray table function EventHelper:ExecuteEvent(eventID,callerObj,simulateOnly,valuesArray) local callList=self.eventListenersDict[eventID] local callerID=self:GetCallerID(callerObj) if not simulateOnly then if self.showDebug then Logger:Trace("Executing:"..eventID..";by:"..callerID,glMsgType.EVENT) end end foreach(callList,function(v,listenerID) if not simulateOnly then if self.showDebug then Logger:Trace(" Listener:"..listenerID,glMsgType.EVENT) end end v.func(eventID,callerObj,simulateOnly,valuesArray) end) end function EventHelper:GetCallerID(callerObj) return (callerObj and (type(callerObj)=="table" and (callerObj.id or (callerObj.name or callerObj)) or callerObj) or "NIL") end -- DebugHelper CLASS DebugHelper={} DebugHelper.__index=DebugHelper DebugHelper.id="DebugHelper" function DebugHelper:Init() if not glDebugMode then Logger.logLvl=Logger.levels.INFO --Logger:RegisterToIgnore(glMsgType.LOGGER) --Logger:RegisterToIgnore(glMsgType.INIT_BASE) --Logger:RegisterToIgnore(glMsgType.INIT_GAME) Logger:RegisterToIgnore(glMsgType.GUI) --Logger:RegisterToIgnore(glMsgType.GAME_LOGIC) Logger:RegisterToIgnore(glMsgType.TUTORIAL) --Logger:RegisterToIgnore(glMsgType.AI) --Logger:RegisterToIgnore(glMsgType.TAG) Logger:RegisterToIgnore(glMsgType.EVENT) Logger:RegisterToIgnore(glMsgType.DEBUG_HELPER) EventHelper.showDebug=false else Logger.logLvl=Logger.levels.TRACE --Logger:RegisterToIgnore(glMsgType.LOGGER) --Logger:RegisterToIgnore(glMsgType.INIT_BASE) --Logger:RegisterToIgnore(glMsgType.INIT_GAME) --Logger:RegisterToIgnore(glMsgType.GUI) --Logger:RegisterToIgnore(glMsgType.GAME_LOGIC) --Logger:RegisterToIgnore(glMsgType.TUTORIAL) Logger:RegisterToIgnore(glMsgType.AI) --Logger:RegisterToIgnore(glMsgType.TAG) --Logger:RegisterToIgnore(glMsgType.EVENT) --Logger:RegisterToIgnore(glMsgType.DEBUG_HELPER) --Logger:RegisterToIgnore(glMsgType.SFX) --Logger:RegisterToIgnore(glMsgType.MUSIC) EventHelper.showDebug=true end DebugHelper:RegisterAllEvents() end function DebugHelper:RegisterAllEvents() EventHelper:RegisterListenerToEvent(glEventTypes.TUTORIAL_INIT,self,self.TutorialInitDealtFunc) EventHelper:RegisterListenerToEvent(glEventTypes.MATCH_STARTED,self,self.MatchStartedDealtFunc) EventHelper:RegisterListenerToEvent(glEventTypes.DAMAGE_DEALT,self,self.DamageDealtFunc) EventHelper:RegisterListenerToEvent(glEventTypes.UNIT_SUMMONED,self,self.UnitSummonedEventFunc) EventHelper:RegisterListenerToEvent(glEventTypes.UNIT_WAS_ATTACKED,self,self.UnitWasAttackedEventFunc) EventHelper:RegisterListenerToEvent(glEventTypes.UNIT_DIED,self,self.UnitDiedEventFunc) --this is called *outside* DestroyUnit(), when I get to passing more info into events, refactor this EventHelper:RegisterListenerToEvent(glEventTypes.CARD_DRAWN,self,self.DeckCreatedEventFunc) EventHelper:RegisterListenerToEvent(glEventTypes.SPELL_CASTED_ON,self,self.SpellCastedOnEventFunc) EventHelper:RegisterListenerToEvent(glEventTypes.TURN_ENDED,self,self.TurnEndedOnEventFunc) EventHelper:RegisterListenerToEvent(glEventTypes.DECK_CREATED,self,self.DeckCreatedEventFunc) EventHelper:RegisterListenerToEvent(glEventTypes.LEADER_CREATED,self,self.LeaderCreatedEventFunc) end function DebugHelper.MatchStartedDealtFunc(eventID,callerObj,simulateOnly,valuesArray) DebugHelper.BaseEventFunc(eventID,callerObj,simulateOnly,valuesArray,function() return "" end) end function DebugHelper.TutorialInitDealtFunc(eventID,callerObj,simulateOnly,valuesArray) DebugHelper.BaseEventFunc(eventID,callerObj,simulateOnly,valuesArray,function() return ";Phase:"..valuesArray.phase end) end function DebugHelper.LeaderCreatedEventFunc(eventID,callerObj,simulateOnly,valuesArray) DebugHelper.BaseEventFunc(eventID,callerObj,simulateOnly,valuesArray,function() local leader=valuesArray.cardObj return ";isPlayer:"..(leader.isPlayerCard and "Y" or "N")..";Leader:"..leader.id..";with stats:"..leader.stats.attack.max..";"..leader.stats.hp.max..";"..leader.stats.armor.max..";tags:"..(#leader.tags) end) end function DebugHelper.DamageDealtFunc(eventID,callerObj,simulateOnly,valuesArray) DebugHelper.BaseEventFunc(eventID,callerObj,simulateOnly,valuesArray,function() return ";isPlayer:"..(valuesArray.cardObj.isPlayerCard and "Y" or "N")..";cardAttacked:"..valuesArray.cardObj.id..";attackedBy:"..(valuesArray.initingObj and valuesArray.initingObj.id or "NIL")..";value:"..valuesArray.amountDealt end) end function DebugHelper.UnitSummonedEventFunc(eventID,callerObj,simulateOnly,valuesArray) DebugHelper.BaseEventFunc(eventID,callerObj,simulateOnly,valuesArray,function() return ";isPlayer:"..(valuesArray.isPlayerCard and "Y" or "N")..";isLeader:"..(valuesArray.isLeaderCard and "Y" or "N") end) end function DebugHelper.UnitWasAttackedEventFunc(eventID,callerObj,simulateOnly,valuesArray) DebugHelper.BaseEventFunc(eventID,callerObj,simulateOnly,valuesArray,function() return ";cardAttacked:"..valuesArray.cardObj.id..";attackedBy:"..valuesArray.initingObj.id end) end function DebugHelper.UnitDiedEventFunc(eventID,callerObj,simulateOnly,valuesArray) DebugHelper.BaseEventFunc(eventID,callerObj,simulateOnly,valuesArray,function() return ";isPlayer:"..(valuesArray.cardObj.isPlayerCard and "Y" or "N")..";cardDying:"..valuesArray.cardObj.id end) end function DebugHelper.CardDrawnEventFunc(eventID,callerObj,simulateOnly,valuesArray) DebugHelper.BaseEventFunc(eventID,callerObj,simulateOnly,valuesArray,function() return ";isPlayer:"..(valuesArray.cardObj.isPlayerCard and "Y" or "N")..";cardDrawn:"..valuesArray.cardObj.id..";cardsOnHand:"..valuesArray.cardsOnHandNum..";cardsLeftInDeck:"..valuesArray.cardsLeftInDeckNum end) end function DebugHelper.SpellCastedOnEventFunc(eventID,callerObj,simulateOnly,valuesArray) DebugHelper.BaseEventFunc(eventID,callerObj,simulateOnly,valuesArray,function() return ";castedOnID:"..valuesArray.cardObj.id..";byCardID:"..valuesArray.initingObj.id end) end function DebugHelper.TurnEndedOnEventFunc(eventID,callerObj,simulateOnly,valuesArray) DebugHelper.BaseEventFunc(eventID,callerObj,simulateOnly,valuesArray,function() return ";forPlayer:"..(valuesArray.forPlayer and "Y" or "N") end) end function DebugHelper.DeckCreatedEventFunc(eventID,callerObj,simulateOnly,valuesArray) DebugHelper.BaseEventFunc(eventID,callerObj,simulateOnly,valuesArray,function() return ";forPlayer:"..(valuesArray.forPlayer and "Y" or "N")..";deckLen:"..#(valuesArray.deck or {})..";handLen:"..#(valuesArray.hand or {}) end) end ---@ messageFunc function so event will try to use valuesArray only if its not simulation - as this will not have all variables function DebugHelper.BaseEventFunc(eventID,callerObj,simulateOnly,valuesArray,messageFunc) if not simulateOnly then local str=DebugHelper.GetBaseEventLogString(eventID,callerObj,simulateOnly,valuesArray) str=str..messageFunc() Logger:Debug(str,glMsgType.DEBUG_HELPER) return str end return "" end function DebugHelper.GetBaseEventLogString(eventID,callerObj,simulateOnly,valuesArray) local callerID=EventHelper:GetCallerID(callerObj) return eventID..";by:"..callerID end -- GUIScenarioStepCreator CLASS GUIScenarioStepCreator = {} GUIScenarioStepCreator.__index=GUIScenarioStepCreator GUIScenarioStepCreator.id="GUIScenarioStepCreator" GUIScenarioStepCreator.stepType={ SCREEN="Screen", BUTTON="Button", ASYNC_LOGIC="AsyncLogic", } function GUIScenarioStepCreator:Init() self.msgType=glMsgType.STEP_GUI_CREATOR end function GUIScenarioStepCreator:CreateStep(stepType,stepArr) if not table.contains(self.stepType,stepType) then Logger:Error("NOT SUPPORTED STEP TYPE:"..stepType,self.msgType) end local step=stepArr or {} step.name=stepType step.processFunc=self["create"..stepType.."Func"] step.revertFunc=self["revert"..stepType.."Func"] step.ifNotFirstStepFunc=GUIScenarioStepCreator.baseIfNotFirstStepFunc step.costOfTheStep=step.costOfTheStep or 1 Logger:Debug("STEP:"..stepType,self.msgType) return step end function GUIScenarioStepCreator.baseIfNotFirstStepFunc(currentStep,steps) if not steps then Logger:Error("No scenario data",GUIScenarioStepCreator.msgType) end currentStep.parent=steps[1].returnArr[1] end function GUIScenarioStepCreator:baseCreate(createFunc,data) Logger:Trace(self.msgType,"CREATING "..data.name,self.msgType) data=createFunc(data) Logger:Trace(self.msgType,"FINISHED "..data.name,self.msgType) return data end function GUIScenarioStepCreator:baseRevert(revertFunc,data) Logger:Debug(self.msgType,"REVERTING "..data.name,self.msgType) local returned=data.returnArr[1] if not returned then Logger:Debug(self.msgType,"NOTHING TO REVERT",self.msgType) end revertFunc(data) Logger:Debug(self.msgType,"REVERTED "..data.name,self.msgType) end function GUIScenarioStepCreator.createScreenFunc(stepData) local func=function(data) local frame=GUIHelper:CreateGUIFrame(data.controlName,data.x,data.y,data.w,data.h,data.style) if data.text then --TODO: look here! frame:Content(GUIHelper.TextLogContentFunction) GUIHelper:InsertUnparsedTextIntoTextGUIFrame(data.text,frame) end data.returnArr={frame} return data end return GUIScenarioStepCreator:baseCreate(func,stepData) end function GUIScenarioStepCreator.createAsyncLogicFunc(stepData) local func=function(data) AsyncQueueLogicHelper:AddToQueue(data.func,data,data.time) end return GUIScenarioStepCreator:baseCreate(func,stepData) end function GUIScenarioStepCreator.revertScreenFunc(stepData) local func=function(data) Logger:Error("IMPLEMENT REVERT OPTION") end return GUIScenarioStepCreator:baseRevert(func,stepData) end function GUIScenarioStepCreator.revertScreenFunc(stepData) local func=function(data) local scr=data.returnArr[1] scr:hide() scr:remove() end GUIScenarioStepCreator:baseRevert(func,stepData) end function GUIScenarioStepCreator.createButtonFunc(stepData) local func=function(data) local button=GUIHelper:CreateButtonWidget(data.parent.name.."_Button_"..data.text,data.x,data.y,data.w,data.h,data.style,data.parent,data.text) button:addParent(data.parent) button.onCleanRelease=data.onCleanReleaseFunc data.returnArr={button} return data end return GUIScenarioStepCreator:baseCreate(func,stepData) end function GUIScenarioStepCreator.revertButtonFunc(stepData) local func=function(data) local btn=data.returnArr[1] btn:hide() btn:remove() end GUIScenarioStepCreator:baseRevert(func,stepData) end -- GUIScenarioCreator CLASS GUIScenarioCreator = {} GUIScenarioCreator.__index=GUIScenarioCreator GUIScenarioCreator.id="GUIScenarioCreator" GUIScenarioCreator.scenarioType={ CHOOSE_SEED="SeedScreen", } function GUIScenarioCreator:Init() self.msgType=glMsgType.SCENARIO_GUI_CREATOR end function GUIScenarioCreator:CreateScenario(scenarioType) if not table.contains(self.scenarioType,scenarioType) then Logger:Error("NOT SUPPORTED SCENARIO TYPE:"..scenarioType,self.msgType) end local scenario={} scenario.name=scenarioType scenario.numberOfTries=0 scenario.stepNumber=1 local steps={} steps=self["create"..scenarioType.."Steps"](self) scenario.steps=steps scenario.currentStepData=steps[1] scenario.processStepFunc=self.baseProcessStepFunc return scenario end function GUIScenarioCreator.baseProcessStepFunc(scenarioData) local num=scenarioData.stepNumber local currentStep=scenarioData.steps[num] if not currentStep then Logger:Error("no step data avail.!",GUIScenarioCreator.msgType) return end Logger:Debug("step:"..scenarioData.stepNumber,GUIScenarioCreator.msgType) if num>1 then currentStep:ifNotFirstStepFunc(scenarioData.steps) end local done=currentStep:processFunc() if not done then Logger:Error("not done!",GUIScenarioCreator.msgType) return false end num=num+1 scenarioData.stepNumber=num scenarioData.numberOfTries=0 return true end function GUIScenarioCreator:createSeedScreenSteps() local steps={} local stepType=GUIScenarioStepCreator.stepType.SCREEN local step={ controlName="ChooseSeedScreen", x=0, y=0, w=glScreenPixelWidth, h=glScreenPixelHeight, style=glBackgroundStaticVioletGUIStyle, } step=GUIScenarioStepCreator:CreateStep(stepType,step) table.insert(steps,step) for i = 0, 69, 1 do stepType=GUIScenarioStepCreator.stepType.BUTTON step={ x=2+(i%7)*33, y=2+math.floor(i/7)*13, w=30, h=10, style=glGUIFrameStyleActiveOKCard, text=i.."", onCleanReleaseFunc=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref) InitSeed(ref.text,true) ref.parent:hide() ref.parent:remove() end } step=GUIScenarioStepCreator:CreateStep(stepType,step) table.insert(steps,step) end return steps end -- GUIScenarioQueueSystem CLASS GUIScenarioQueueSystem = {} GUIScenarioQueueSystem.__index=GUIScenarioQueueSystem GUIScenarioQueueSystem.id="GUIScenarioQueueSystem" GUIScenarioQueueSystem.queue={} GUIScenarioQueueSystem.pointsPerFrame=10 function GUIScenarioQueueSystem:Init() self.msgType=glMsgType.SCENARIO_GUI self.availPointsForFrame=GUIScenarioQueueSystem.pointsPerFrame end function GUIScenarioQueueSystem:RegisterScenario(scenarioData) Logger:Debug("Registering scenario:"..scenarioData.name,self.msgType) table.insert(self.queue,scenarioData) end function GUIScenarioQueueSystem:CanUpdate() return #(self.queue)>0 and self.availPointsForFrame>0 end function GUIScenarioQueueSystem:EndOfProcessing() self.availPointsForFrame=self.pointsPerFrame end function GUIScenarioQueueSystem:ProcessOnce(deltaTime) if not self:CanUpdate() then return end local avPoints=self.availPointsForFrame if avPoints<=0 then return end for i=#self.queue,1,-1 do local scenarioData=self.queue[i] if not scenarioData then Logger:Debug("no scenario",self.msgType) table.remove(self.queue,i) end local stepNum=scenarioData.stepNumber local stepData=scenarioData.steps[stepNum] local stepPoints=stepData.costOfTheStep if stepPoints<=avPoints and stepData then local reqFunc = scenarioData.RequirementsFulfilled if not reqFunc or reqFunc(scenarioData) then if stepNum<=1 then Logger:Debug("Starting scenario:"..scenarioData.name,self.msgType) if scenarioData.onScenarioStartFunc then scenarioData:onScenarioStartFunc(scenarioData) end end local stepDone=scenarioData:processStepFunc(allTheLogicItMayRequire) if stepDone then stepNum=scenarioData.stepNumber stepData=scenarioData.steps[stepNum] self.availPointsForFrame=avPoints-stepPoints if not stepData then Logger:Debug("Finished scenario:"..scenarioData.name,self.msgType) if scenarioData.onScenarioEndFunc then scenarioData:onScenarioEndFunc() end table.remove(self.queue,i) end else Logger:Error("STEP_NOT_FINISHED;"..scenarioData.name..";"..stepData.id..";"..stepData.name,self.msgType) scenarioData.numberOfTries=step.numberOfTries+1 if scenarioData.onScenarioErrorFunc then scenarioData:onScenarioErrorFunc(scenarioData) end if scenarioData.numberOfTries>=self.numberOfTriesForStep then Logger:Error("REVERTING_CHANGES;"..scenarioData.name,self.msgType) if scenarioData.onScenarioErrorFunc then scenarioData:onScenarioErrorFunc(scenarioData) end scenarioData:RevertChanges() table.remove(self.queue,i) end end end end end end -- QueueHelper CLASS QueueHelper = {} QueueHelper.__index=QueueHelper QueueHelper.id="QueueHelper" QueueHelper.queue={} function QueueHelper:Update(deltaTime) if #self.queue==0 then return end for i=#self.queue,1,-1 do local elem=self.queue[i] if elem then if elem.timeToStartInSecs<=0 then if elem.func(elem.dataTable) then table.remove(self.queue,i) else break end end elem.timeToStartInSecs=math.round(elem.timeToStartInSecs-deltaTime,2) end end end function QueueHelper:AddToQueue(f,data,delayInSecs) table.insert(self.queue,{func=f,dataTable=data,timeToStartInSecs=(delayInSecs and delayInSecs or 0)}) end -- AsyncQueueLogicHelper CLASS AsyncQueueLogicHelper = {} AsyncQueueLogicHelper.__index=AsyncQueueLogicHelper AsyncQueueLogicHelper.id="AsyncQueueLogicHelper" AsyncQueueLogicHelper.queue={} function AsyncQueueLogicHelper:Update(deltaTime) if #self.queue==0 then return end for i=#self.queue,1,-1 do local elem=self.queue[i] if elem then if elem.timeToStartInSecs<=0 then elem.func(elem.dataTable) table.remove(self.queue,i) end elem.timeToStartInSecs=math.round(elem.timeToStartInSecs-deltaTime,2) end end end function AsyncQueueLogicHelper:AddToQueue(f,data,delayInSecs) table.insert(self.queue,{func=f,dataTable=data,timeToStartInSecs=(delayInSecs and delayInSecs or 0)}) end -- AsyncQueueDrawHelper CLASS AsyncQueueDrawHelper = {} AsyncQueueDrawHelper.__index=AsyncQueueDrawHelper AsyncQueueDrawHelper.id="AsyncQueueDrawHelper" AsyncQueueDrawHelper.queue={} function AsyncQueueDrawHelper:Update(deltaTime) if #self.queue==0 then return end for i=#self.queue,1,-1 do local elem=self.queue[i] if elem then if elem.timeToStartInSecs<=0 then elem.func(elem.dataTable) table.remove(self.queue,i) end elem.timeToStartInSecs=math.round(elem.timeToStartInSecs-deltaTime,2) end end end function AsyncQueueDrawHelper:AddToQueue(f,data,delayInSecs) table.insert(self.queue,{func=f,dataTable=data,timeToStartInSecs=(delayInSecs and delayInSecs or 0)}) end -- PARTICLEHELPER CLASS ParticleHelper = {} ParticleHelper.__index=ParticleHelper ParticleHelper.id="ParticleHelper" ParticleHelper.spellsEnum={ EXPLOSION=1, BLOOD=2, SMOKE=3, QUICK_SMOKE_BLACK=4, SPARKS=5, HEAL=6, QUICK_SMOKE_WHITE=7, MANA_REST=8, MANA_BUFF=9, MANA_CUT=10, HP_BUFF=11, HP_CUT=12, ATK_BUFF=13, ATK_CUT=14, ARMOR_BUFF=15, ARMOR_CUT=16, MOUSE_SPELL_NO_INTERACTION=17, MOUSE_SPELL_INTERACTED=18, MANA_SPARKS_GAIN=19, MANA_SPARKS_SPEND=20, WATERFALL=21, SPELLPWR_BUFF=22, SPELLPWR_CUT=23, REMOVE_TAG=24, } function ParticleHelper.ExecuteFXFunc(data) local self=ParticleHelper if data.id==self.spellsEnum.EXPLOSION then make_explosion_ps(data.x,data.y,data.strength,GameHelper.animationSpeed) elseif data.id==self.spellsEnum.BLOOD then make_blood_ps(data.x,data.y,GameHelper.animationSpeed,data.minVX,data.maxVX,data.minVX,data.maxVY,data.stopZone,data.strength,data.color) elseif data.id==self.spellsEnum.SMOKE then make_smoke_ps(data.x,data.y,GameHelper.animationSpeed) elseif data.id==self.spellsEnum.QUICK_SMOKE_BLACK then make_quick_smoke_ps(data.x,data.y,GameHelper.animationSpeed,{1,3,2}) elseif data.id==self.spellsEnum.MOUSE_SPELL_NO_INTERACTION then make_mouse_spell_interacted_basic_ps(data.x,data.y,GameHelper.animationSpeed) elseif data.id==self.spellsEnum.MOUSE_SPELL_INTERACTED then make_mouse_spell_interacted_with_gui_ps(data.x,data.y,GameHelper.animationSpeed) elseif data.id==self.spellsEnum.MANA_SPARKS_GAIN then make_mana_sparks_gain_ps(data.x,data.y,GameHelper.animationSpeed) elseif data.id==self.spellsEnum.MANA_SPARKS_SPEND then make_mana_sparks_spend_ps(data.x,data.y,GameHelper.animationSpeed) elseif data.id==self.spellsEnum.SPARKS then make_sparks_ps(data.x,data.y,GameHelper.animationSpeed) elseif data.id==self.spellsEnum.HEAL then make_healBubbles_ps(data.x,data.y,GameHelper.animationSpeed) elseif data.id==self.spellsEnum.QUICK_SMOKE_WHITE then make_quick_smoke_ps(data.x,data.y,GameHelper.animationSpeed,{7,7,15}) elseif data.id==self.spellsEnum.MANA_REST then make_buffCutBubbles_ps(data.x,data.y,GameHelper.animationSpeed,274,259) elseif data.id==self.spellsEnum.MANA_BUFF then make_buffCutBubbles_ps(data.x,data.y,GameHelper.animationSpeed,274,499) elseif data.id==self.spellsEnum.MANA_CUT then make_buffCutBubbles_ps(data.x,data.y,GameHelper.animationSpeed,274,502) elseif data.id==self.spellsEnum.HP_BUFF then make_buffCutBubbles_ps(data.x,data.y,GameHelper.animationSpeed,276,504) elseif data.id==self.spellsEnum.HP_CUT then make_buffCutBubbles_ps(data.x,data.y,GameHelper.animationSpeed,276,503) elseif data.id==self.spellsEnum.ATK_BUFF then make_buffCutBubbles_ps(data.x,data.y,GameHelper.animationSpeed,277,506) elseif data.id==self.spellsEnum.ATK_CUT then make_buffCutBubbles_ps(data.x,data.y,GameHelper.animationSpeed,277,501) elseif data.id==self.spellsEnum.ARMOR_BUFF then make_buffCutBubbles_ps(data.x,data.y,GameHelper.animationSpeed,275,505) elseif data.id==self.spellsEnum.ARMOR_CUT then make_buffCutBubbles_ps(data.x,data.y,GameHelper.animationSpeed,275,500) elseif data.id==self.spellsEnum.WATERFALL then make_waterfall_ps(data.startX,data.startY,data.endX,data.endY,data.strength,GameHelper.animationSpeed) elseif data.id==self.spellsEnum.SPELLPWR_BUFF then make_buffCutBubbles_ps(data.x,data.y,GameHelper.animationSpeed,278,492) elseif data.id==self.spellsEnum.SPELLPWR_CUT then make_buffCutBubbles_ps(data.x,data.y,GameHelper.animationSpeed,278,261) elseif data.id==self.spellsEnum.REMOVE_TAG then make_removeTagBubbles_ps(data.x,data.y,GameHelper.animationSpeed,276,510) end end function ParticleHelper:AddToQueue(fxTable,delayInSecs) AsyncQueueLogicHelper:AddToQueue(self.ExecuteFXFunc,fxTable,delayInSecs) end function ParticleHelper:CreateATKBuffFX(x,y,delayForFX) self:CreateBuffOrCutFX(x,y,self.spellsEnum.ATK_BUFF,delayForFX) end function ParticleHelper:CreateATKCutFX(x,y,delayForFX) self:CreateBuffOrCutFX(x,y,self.spellsEnum.ATK_CUT,delayForFX) end function ParticleHelper:CreateArmorBuffFX(x,y,delayForFX) self:CreateBuffOrCutFX(x,y,self.spellsEnum.ARMOR_BUFF,delayForFX) if GameHelper.tutorialPhase>40 then glEndTurnButton:visible(true) end end function ParticleHelper:CreateArmorCutFX(x,y,delayForFX) self:CreateBuffOrCutFX(x,y,self.spellsEnum.ARMOR_CUT,delayForFX) end function ParticleHelper:CreateHPBuffFX(x,y,delayForFX) self:CreateBuffOrCutFX(x,y,self.spellsEnum.HP_BUFF,delayForFX) end function ParticleHelper:CreateHPCutFX(x,y,delayForFX) self:CreateBuffOrCutFX(x,y,self.spellsEnum.HP_CUT,delayForFX) end function ParticleHelper:CreateManaRestFX(x,y,delayForFX) self:CreateBuffOrCutFX(x,y,self.spellsEnum.MANA_REST,delayForFX) end function ParticleHelper:CreateManaBuffFX(x,y,delayForFX) self:CreateBuffOrCutFX(x,y,self.spellsEnum.MANA_BUFF,delayForFX) end function ParticleHelper:CreateManaCutFX(x,y,delayForFX) self:CreateBuffOrCutFX(x,y,self.spellsEnum.MANA_CUT,delayForFX) end function ParticleHelper:CreateSpellPWRBuffFX(x,y,delayForFX) self:CreateBuffOrCutFX(x,y,self.spellsEnum.SPELLPWR_BUFF,delayForFX) end function ParticleHelper:CreateSpellPWRCutFX(x,y,delayForFX) self:CreateBuffOrCutFX(x,y,self.spellsEnum.SPELLPWR_CUT,delayForFX) end function ParticleHelper:CreateMouseClickWithNoInteractionFX(x,y,delayForFX) self:AddToQueue({id=self.spellsEnum.MOUSE_SPELL_NO_INTERACTION,x=x,y=y},delayForFX) end function ParticleHelper:CreateMouseClickWithInteractionFX(x,y,delayForFX) self:AddToQueue({id=self.spellsEnum.MOUSE_SPELL_INTERACTED,x=x,y=y},delayForFX) end function ParticleHelper:CreateManaFX(x,y,spent,delayForFX) self:AddToQueue({id=(spent and ParticleHelper.spellsEnum.MANA_SPARKS_SPEND or ParticleHelper.spellsEnum.MANA_SPARKS_GAIN),x=x,y=y},delayForFX) end function ParticleHelper:CreateBuffOrCutFX(x,y,spellsEnum,delayForFX) self:AddToQueue({id=spellsEnum,x=x-10,y=y},delayForFX) self:AddToQueue({id=spellsEnum,x=x,y=y},delayForFX+0.2) self:AddToQueue({id=spellsEnum,x=x+10,y=y},delayForFX+0.4) end function ParticleHelper:CreateHealingFX(x,y,delayForFX) self:AddToQueue({id=self.spellsEnum.HEAL,x=x,y=y},delayForFX) self:AddToQueue({id=self.spellsEnum.HEAL,x=x,y=y},delayForFX+0.2) self:AddToQueue({id=self.spellsEnum.HEAL,x=x,y=y},delayForFX+0.4) end function ParticleHelper:CreateSummoningCardFX(x,y,delayForFX) delayForFX= delayForFX or 0 self:AddToQueue({id=self.spellsEnum.QUICK_SMOKE_WHITE,x=x,y=y},delayForFX) self:AddToQueue({id=self.spellsEnum.QUICK_SMOKE_WHITE,x=x-10,y=y},delayForFX) self:AddToQueue({id=self.spellsEnum.QUICK_SMOKE_WHITE,x=x+12,y=y},delayForFX) end function ParticleHelper:CreateSummoningUnitFX(x,y) delayForFX= delayForFX or 0 self:AddToQueue({id=self.spellsEnum.QUICK_SMOKE_BLACK,x=x,y=y},delayForFX) self:AddToQueue({id=self.spellsEnum.QUICK_SMOKE_BLACK,x=x-10,y=y},delayForFX) self:AddToQueue({id=self.spellsEnum.QUICK_SMOKE_BLACK,x=x+10,y=y},delayForFX) end function ParticleHelper:CreateWoundedFX(x,y,unitPosX,unitPosY,strength,stopZone,color,delayTime) unitPosX=unitPosX and unitPosX or 1 local middlePosOffset=(4-unitPosX) local maxDeviation=4 self:AddToQueue({id=self.spellsEnum.BLOOD, x=x,y=y, minVX=middlePosOffset/3-0.5-(maxDeviation-math.abs(middlePosOffset)), maxVX=middlePosOffset/3+0.5+(maxDeviation-math.abs(middlePosOffset)), minVY=nil, maxVY=nil,strength=strength,stopZone=stopZone,color=color},delayTime) end function ParticleHelper:CreateArmorDamagedFX(x,y,delayTime) self:AddToQueue({id=self.spellsEnum.SPARKS,x=x,y=y},delayTime) end function ParticleHelper:CreateFireballFX(startX,startY,endX,endY,spellPower,delay) local diffX=endX-startX local diffY=endY-startY delay=delay and delay or 0 for n=0,9 do self:AddToQueue({id=self.spellsEnum.EXPLOSION,x=(startX+(diffX/10)*n),y=(startY+(diffY/10)*n),spellPower},delay+0.03*n+(0.01)*(2-GameHelper.animationSpeed)) end end function ParticleHelper:CreateWaterfallFX(startX,startY,endX,endY,spellPower,delayTime) self:AddToQueue({id=self.spellsEnum.WATERFALL,startX=startX,startY=startY,endX=endX,endY=endY,strength=spellPower},delayTime) end function ParticleHelper:CreateDeathFX(x,y,delayTime) self:AddToQueue({id=self.spellsEnum.EXPLOSION,x=x,y=y},delayTime) self:AddToQueue({id=self.spellsEnum.EXPLOSION,x=x-5,y=y},delayTime) self:AddToQueue({id=self.spellsEnum.EXPLOSION,x=x+5,y=y},delayTime) end function ParticleHelper:CreateRemoveTagFX(x,y,delayTime) self:AddToQueue({id=self.spellsEnum.REMOVE_TAG,x=x,y=y},delayTime) self:AddToQueue({id=self.spellsEnum.REMOVE_TAG,x=x-5,y=y},delayTime) self:AddToQueue({id=self.spellsEnum.REMOVE_TAG,x=x+5,y=y},delayTime) end -- SCOREHELPER CLASS ScoreHelper = {} ScoreHelper.__index=ScoreHelper ScoreHelper.id="ScoreHelper" -- RULEHELPER CLASS RuleHelper = {} RuleHelper.__index=RuleHelper RuleHelper.id="RuleHelper" -- AIHELPER CLASS AIHelper = {} AIHelper.__index=AIHelper AIHelper.id="AIHelper" AIHelper.doneMoveThisTurn=false AIHelper.attackedThisTurn=false AIHelper.summonedThisTurn=false AIHelper.castedThisTurn=false AIHelper.ignorePoisonOnMoves=true AIHelper.movesEnum={ DO_NOTHING="DO_NOTHING", ATTACK_WITH_LEADER="ATTACK_WITH_LEADER", ATTACK_WITH_UNIT="ATTACK_WITH_UNIT", SUMMON_UNIT="SUMMON_UNIT", CAST_SPELL="CAST_SPELL", } function AIHelper:ExecuteTurn(deltaTime) if self.turnFinished then self.doneMoveThisTurn=false self.attackedThisTurn=false self.summonedThisTurn=false self.castedThisTurn=false return end local tutorialAI=GameHelper.tutorialPhase>0 if self.AIDifficulty==0 or tutorialAI then --will always behave the same, spends mana, attacks with units if possible, always in same order and manner, doesnt use spells? if not self.currentTurnMoveList then self.currentTurnMoveList=self:GetAvailMovesList(GameHelper.enemyHandCards,GameHelper.enemyLeaderCard,GameHelper.enemyBattlefieldCards,GameHelper.playerLeaderCard,GameHelper.playerBattlefieldCards) Logger:Trace("SIMPLE: GENERATE MOVE LIST:"..(#self.currentTurnMoveList),glMsgType.AI) end if self:ProcessTurnSimple(deltaTime,self.currentTurnMoveList) then self.currentTurnMoveList=nil end else self:ProcessTurnNormal(deltaTime) end end function AIHelper:GetAvailMovesList(aiHandCards,aiLeaderCard,aiBattlefieldCards,playerLeaderCard,playerBattlefieldCards) local moves={} local aiLeaderStats=aiLeaderCard.stats local tutorialAI=GameHelper.tutorialPhase>39 Logger:Debug("BASE: GENERATING AVAIL. MOVES",glMsgType.AI) Logger:Trace(" AI BATTLEFIELD UNITS:"..(#aiBattlefieldCards),glMsgType.AI) Logger:Trace(" AI HAND CARDS:"..(#aiHandCards),glMsgType.AI) Logger:Trace(" PLAYER BATTLEFIELD UNITS:"..(#playerBattlefieldCards),glMsgType.AI) foreach(aiBattlefieldCards,function(aiUnit) local nOfAtks=aiUnit.stats.attacksAvail.cur if aiUnit:CanExecuteAttack(true) then if playerLeaderCard:CanBeAttacked(playerBattlefieldCards,aiUnit,tru„e) then for i=1,nOfAtks do table.insert(moves,{id=self.movesEnum.ATTACK_WITH_UNIT,data={executingCard=aiUnit,targetCard=playerLeaderCard}}) end end foreach(playerBattlefieldCards,function(playerUnit) local tutReq=((not tutorialAI or GameHelper.tutorialPhase<49 and playerUnit.stats.hp.cur~=1) or (GameHelper.tutorialPhase==49 and playerUnit.stats.armor.cur>0)) Logger:Trace(" TUTORIAL REQ:"..(tutReq and 1 or 0),glMsgType.AI) if playerUnit:CanBeAttacked(playerBattlefieldCards,aiUnit,true) and tutReq then --making sure tutorial 4 venom unit will only attack healthy units to show how tag works for i=1,nOfAtks do table.insert(moves,{id=self.movesEnum.ATTACK_WITH_UNIT,data={executingCard=aiUnit,targetCard=playerUnit}}) end end end) end end) foreach(aiHandCards,function(aiHandCard) if aiLeaderStats.manaCount.cur>=aiHandCard.stats.manaCost.cur then if aiHandCard.isSpell then local targets=deepcopy(glGameTarget) if table.contains(targets,glGameTarget.ANY_LEADER) then table.insert(moves,{id=self.movesEnum.CAST_SPELL,data={executingCard=aiHandCard,targetCard=playerLeaderCard}}) table.insert(moves,{id=self.movesEnum.CAST_SPELL,data={executingCard=aiHandCard,targetCard=aiLeaderCard}}) end if table.contains(targets,glGameTarget.ANY_UNIT) then foreach(playerBattlefieldCards,function(playerUnit) if playerUnit then table.insert(moves,{id=self.movesEnum.CAST_SPELL,data={executingCard=aiHandCard,targetCard=playerUnit}}) end end) foreach(aiBattlefieldCards,function(aiUnit) if aiUnit then table.insert(moves,{id=self.movesEnum.CAST_SPELL,data={executingCard=aiHandCard,targetCard=aiUnit}}) end end) end --todo: add support for spells that targets cards in hand else if #aiBattlefieldCards<6 and not aiHandCard.isFatiqueCard then table.insert(moves,{id=self.movesEnum.SUMMON_UNIT,data={executingCard=aiHandCard}}) end end end end) if aiLeaderCard:CanExecuteAttack() then local nOfAtks=aiLeaderCard.stats.attacksAvail.cur foreach(playerBattlefieldCards,function(playerUnit) local tutorialAICanAttack=playerUnit:GetTagByName(glUnitTags.DISTRACT.name) if playerUnit:CanBeAttacked(playerBattlefieldCards,aiLeaderCard,true) and (not tutorialAI or tutorialAICanAttack) then --making sure ai leader in tutorial 4 will always attack player leader unless distract tag for i=1,nOfAtks do table.insert(moves,{id=self.movesEnum.ATTACK_WITH_LEADER,data={executingCard=aiLeaderCard,targetCard=playerUnit}}) end end end) if playerLeaderCard:CanBeAttacked(playerBattlefieldCards,aiLeaderCard,true) then for i=1,nOfAtks do table.insert(moves,{id=self.movesEnum.ATTACK_WITH_LEADER,data={executingCard=aiLeaderCard,targetCard=playerLeaderCard}}) end end end table.insert(moves,{id=self.movesEnum.DO_NOTHING,data={}}) Logger:Debug("BASE: found possible moves:"..#moves,glMsgType.AI) foreach(moves,function(move) move.score=0 Logger:Trace(" "..move.id,glMsgType.AI) end) return moves end function AIHelper:AssessMoves(aiHandCards,aiLeaderCard,aiBattlefieldCards,playerLeaderCard,playerBattlefieldCards,styleOfPlay) local availMoves=self:GetAvailMovesList(aiHandCards,aiLeaderCard,aiBattlefieldCards,playerLeaderCard,playerBattlefieldCards) local wMoves={} local baseScore=100 if #availMoves==0 then return wMoves end Logger:Debug("EASY: WEIGHING MOVES",glMsgType.AI) local i=0 foreach(availMoves,function(move) Logger:Trace(" WEIGHING MOVE:"..move.id,glMsgType.AI) local score=0 local anyAiUnitHaveHealerTag=false local anyEnemyUnitHaveHealerTag=false --TODO modify those statics to create styles of play local valFor1HP=25 local valForTag=100 local valFor1AtkBonusMinus=50 local valForKillingEnemy=1500 local valForKillingOwnUnit=100 --this will be subtracted TODO: change all calculations to + and make values minus instead local valForKamikazeMult=100 local valForLeaderAttackingLeader=200 local atkDiffBetweenUnitsMultBonusPerPoint=0.1 local atkDiffBetweenUnitAndEnemyLeaderMultBonusPerPoint=0.15 local atkDiffBetweenLeaderAndEnemyUnitsMultBonusPerPoint=0.2 local atkDiffBetweenLeadersMultBonusPerPoint=0.2 local safeLeaderHPPerc=0.8 local valLeaderHPValue=100 local critLeaderHPPerc=0.25 local valLeaderCritHPValueMult=2 local ownLeaderDies=9999999 local saveLeaderModeWhenHpPlusArmorEqualsVal=4 local percTresholdToAttackLeader=0.5 local enemyTagsWeightList={ DASH=0, VENOM=glUnitTags.VENOM.costValue*valForTag*4, POISON=glUnitTags.POISON.costValue*valForTag*3, DISTRACT=glUnitTags.DISTRACT.costValue*valForTag, STEAL=glUnitTags.STEAL.costValue*valForTag, PIERCE=glUnitTags.PIERCE.costValue*valForTag, CLEAVE=glUnitTags.CLEAVE.costValue*valForTag*2.5, DISARM=glUnitTags.DISARM.costValue*valForTag, FEARED=glUnitTags.FEARED.costValue*valForTag*5, HEALER=glUnitTags.HEALER.costValue*valForTag*2, DRAW=0, SUMMON=0, RANGED=glUnitTags.RANGED.costValue*valForTag*2.5, } foreach(aiBattlefieldCards,function(aiCard) if aiCard:GetTagByName(glUnitTags.HEALER.name) then anyAiUnitHaveHealerTag=true end end) foreach(enemyBattlefieldCards,function(aiCard) if aiCard:GetTagByName(glUnitTags.HEALER.name) then anyEnemyUnitHaveHealerTag=true end end) if move.id==self.movesEnum.DO_NOTHING then score=-199+(-400*(self.attackedThisTurn and 1 or 0)) --TODO: add ability to change this as it is threshold for ai on whenever do 'bad moves' over doing nothing and ending turn else local ownUnit=move.data.executingCard:DeepCopy() local ownUnitPoisonedBefore=self.ignorePoisonOnMoves and false or ownUnit:GetTagByName(glUnitTags.POISONED.name)--GameHelper:FindTagInCard(ownUnit,glUnitTags.POISONED.name) local ownUnitIsLeader=ownUnit.isLeaderCard if move.id==self.movesEnum.SUMMON_UNIT then elseif move.id==self.movesEnum.CAST_SPELL then --determine if spell is offensive + or defensive - local spellWeightList={ DAMAGE=10, HEAL=-150, MANAREST=0, BUFF=-1000, CUT=1000, BUFF_MANA=-7000, BUFF_ATK=-100, BUFF_ARMOR=-250, BUFF_HP=-200, SUMMON=-500, SUMMON_U011=-500, SUMMON_U001=-500, CUT_HP=200, CUT_MANA=100, CUT_ATK=300, CUT_ARMOR=250, REMOVETAG_FIRST=200, REMOVETAG_LAST=200, DRAW=-100, APPLY_POISONED=500, APPLY_DISTRACT=500, APPLY_SLOW=500, } local ownSpell=ownUnit local targetUnitHPBefore=move.data.targetCard.stats.hp.cur local targetUnit=move.data.targetCard:DeepCopy() local targetUnitPoisonedBefore=self.ignorePoisonOnMoves and false or targetUnit:GetTagByName(glUnitTags.POISONED.name)--GameHelper:FindTagInCard(targetUnit,glUnitTags.POISONED.name) local targetUnitHPPercent=targetUnit.stats.hp:percent() local targetUnitArmorBefore=targetUnit.stats.armor.cur local targetUnitLifeBefore=targetUnitHPBefore+targetUnitArmorBefore local targetIsPlayer=targetUnit.isPlayerCard local targetIsLeader=targetUnit.isLeaderCard local spellPower=ownSpell.stats.spellPower.cur if targetUnitHPBefore<=0 then score=-999999 else local removeTagLogic=function(isFirst,targetCard) local isLeader=targetCard.isLeaderCard local tag=targetCard.tags[isFirst and 1 or (isLeaderCard and 6 or 3)] if not tag then return end if targetCard.isPlayerCard then return (tag.costValue<0 and 100 or -100)*(isLeader and 10 or 1) else return (tag.costValue>0 and 100 or -100)*(isLeader and 10 or 1) end end foreach(ownSpell.tags,function(tag) local n=tag.name local val=spellWeightList[n] if tag.data and tag.data.split then val=spellWeightList[n.."_"..tag.data.split[1]] end --allow specified version to be fetched first if not val then val=spellWeightList[n] end if val then score=score+val if n=="DAMAGE" then if targetUnitHPBefore<=spellPower then score=200 end elseif n=="HEAL" then if ownUnitHPPercent==1 then score=-1000 end elseif n=="ATKBUFF" then if targetIsLeader then score=score*10 end elseif string.find(n,"BUFF") then score=targetIsPlayer and (targetIsLeader and 100*score or score) or score elseif n=="CUT_MANA" or n=="CUT_ATK" then score=targetIsPlayer and (targetIsLeader and 100*score or score) or score elseif n=="REMOVETAG_FIRST" then score=score+removeTagLogic(true,targetUnit) elseif n=="REMOVETAG_LAST" then score=score+removeTagLogic(false,targetUnit) elseif n=="APPLY_DISTRACT" or n=="APPLY_SLOW" or n=="APPLY_POISONED" then score=targetIsPlayer and (targetIsLeader and 100*score or score) or score end end end) if not targetIsPlayer then --TODO: if score starts to be applied before this spell weight list, it will create wrong scenarios! Logger:Trace("%%%%%%%% reversing score because it is applied on own unit:",glMsgType.AI) score=score*-1 end end elseif move.id==self.movesEnum.ATTACK_WITH_UNIT or move.id==self.movesEnum.ATTACK_WITH_LEADER then score=score+100 --bonus for attacking actions local ownUnitHPBefore=ownUnit.stats.hp.cur local ownUnitHPPercent=ownUnit.stats.hp:percent() local ownUnitLifeBefore=ownUnitHPBefore+ownUnit.stats.armor.cur local ownUnitLifePercentBefore=ownUnitLifeBefore/(ownUnit.stats.hp.max+ownUnit.stats.armor.max) local ownUnitPoisonedBefore=self.ignorePoisonOnMoves and false or ownUnit:GetTagByName(glUnitTags.POISONED.name) --GameHelper:FindTagInCard(ownUnit,glUnitTags.POISONED.name) local ownUnitWillDieAnyway=false local enemyUnit=move.data.targetCard:DeepCopy() local enemyUnitPoisonedBefore=self.ignorePoisonOnMoves and false or enemyUnit:GetTagByName(glUnitTags.POISONED.name)--GameHelper:FindTagInCard(enemyUnit,glUnitTags.POISONED.name) local enemyUnitLifeBefore=enemyUnit.stats.hp.cur+enemyUnit.stats.armor.cur local enemyUnitLifePercentBefore=enemyUnit.stats.hp:percent() local valForAttackingEnemyLeader=600 --check for things that discourage/encourage attacking unit before doing it if enemyUnitPoisonedBefore then score=score+math.min(25,-100+enemyUnit.stats.hp.cur*valFor1HP) end local atkDiff=ownUnit.stats.attack.cur-enemyUnit.stats.attack.cur local atkMult=atkDiffBetweenUnitsMultBonusPerPoint if ownUnit.isLeaderCard then atkMult=atkDiffBetweenLeaderAndEnemyUnitsMultBonusPerPoint if enemyUnit.isLeaderCard then atkMult=atkDiffBetweenLeadersMultBonusPerPoint score=score+100+(1-enemyUnitLifePercentBefore)*1000 --valForLeaderAttackingLeader*atkMult+(enemyUnitLifePercentBefore<0.5 and (1-enemyUnitLifePercentBefore)*1000 or 0) end --hp of ai leader is important so with lower total hp, ai leader should be more cautious local hpP=enemyUnit.stats.hp:percent() local hpDiffPerc=hpP-1 local hpCritMult=(hpP<=critLeaderHPPerc and valLeaderCritHPValueMult or 1) score=score-hpDiffPerc*valLeaderHPValue*hpCritMult --todo: add checking if there is a enemy unit with attack higher or equal to leader hp if ownUnitLifeBefore<=saveLeaderModeWhenHpPlusArmorEqualsVal then score=-5555 end if hpP<=percTresholdToAttackLeader then score=score*10 end else if enemyUnit.isLeaderCard then atkMult=atkDiffBetweenUnitAndEnemyLeaderMultBonusPerPoint+(enemyUnitLifePercentBefore<0.5 and (1-enemyUnitLifePercentBefore)*1000 or 0) score=score+600+(1-enemyUnitLifePercentBefore)*1000 end end score=score+math.abs(score)*atkDiff*atkMult --if unit was poisoned before take that into account, and if its going to die anyway, do kamikaze if ownUnitPoisonedBefore and ownUnit.stats.hp.cur<2 and (not ownUnitIsLeader) then ownUnitWillDieAnyway=true --score=score+valForKillingEnemy*valForKamikazeMult*(move.data.targetCard.isPlayerCard and 3 or 1) end --if own unit have PIERCE then it's worth attacking anything with armor if ownUnit:GetTagByName(glUnitTags.PIERCE.name) then score=score+valFor1HP*2*enemyUnit.stats.armor.cur end --if enemy has more attack than one and own unit have DISARM tag if ownUnit:GetTagByName(glUnitTags.DISARM.name) then score=score+valFor1AtkBonusMinus*(enemyUnit.isLeaderCard and 4 or 1)*(enemyUnit.stats.attack.cur-1) end --if enemy unit have one of bad TAGS then add bonus to attacking those over normal ones foreach(enemyUnit.tags,function(tag) local val=enemyTagsWeightList[tag.name] if val then score=score+val end end) Logger:Debug(" score before sim.:"..score,glMsgType.AI) GameHelper:SimulateAttackAction(ownUnit,enemyUnit) local ownUnitPoisonedAfter=self.ignorePoisonOnMoves and false or ownUnit:GetTagByName(glUnitTags.POISONED.name) local enemyUnitPoisonedAfter=self.ignorePoisonOnMoves and false or enemyUnit:GetTagByName(glUnitTags.POISONED.name) local ownUnitLifeAfter=ownUnit.stats.hp.cur+ownUnit.stats.armor.cur local ownUnitLifePercentAfter=ownUnitLifeAfter/(ownUnit.stats.hp.max+ownUnit.stats.armor.max) local ownUnitLifeChangePercent=ownUnitLifePercentBefore-ownUnitLifePercentAfter local enemyUnitLifeAfter=enemyUnit.stats.hp.cur+enemyUnit.stats.armor.cur --determine how your own unit is doing local ownUnitDies=false if ownUnit.isDeleted then ownUnitDies=true score=score- (ownUnitWillDieAnyway and 1 or 100) if ownUnitIsLeader then score=-999999 end else --if enemy has more attack than one and own unit have DISARM tag if ownUnit:GetTagByName(glUnitTags.RANGED.name) then score=1000 else score=score-ownUnit.stats.hp.cur*valFor1HP-(anyEnemyUnitHaveHealerTag and valFor1HP or 0) end end --and compare that to how enemy unit is doing if enemyUnit.isDeleted then score=score+(enemyUnit.isLeaderCard and 999999 or valForKillingEnemy*(ownUnitDies and valForKamikazeMult or 1)) else if enemyUnit.isLeaderCard then score=score+valForAttackingEnemyLeader+(enemyUnitLifeBefore-enemyUnitLifeAfter)*valFor1HP if ownUnit.isLeaderCard then local atkDiff=ownUnit.stats.attack.cur-enemyUnit.stats.attack.cur score=score+atkDiff*valFor1AtkBonusMinus end else score=0-(ownUnit.isLeaderCard and 300 or 0) end if enemyUnitPoisonedAfter then if not enemyUnitPoisonedBefore then --worth poisoning, especially leader score=score+(enemyUnit.isLeaderCard and 1000 or 100) end --TODO: handle more than one poison score=score+valFor1HP if enemyUnit.stats.hp.cur==1 then --will die on end of the turn regardless score=score+(enemyUnit.isLeaderCard and 9999 or valForKillingEnemy) end end end end end local endScore=baseScore+score move.score=endScore table.insert(wMoves,{move=move,score=endScore}) Logger:Debug(" score after sim:"..endScore,glMsgType.AI) i=i+1 end) local weightedSortedMoves={} for k,moveScored in spairs(wMoves, function(t,a,b) return t[b].score < t[a].score end) do table.insert(weightedSortedMoves,moveScored.move) end return weightedSortedMoves end function AIHelper:ProcessTurnNormal(deltaTime) local aiHandCards=GameHelper.enemyHandCards local aiLeaderCard=GameHelper.enemyLeaderCard local aiLeaderStats=aiLeaderCard.stats local aiBattlefieldCards=GameHelper.enemyBattlefieldCards local playerLeaderCard=GameHelper.playerLeaderCard local playerBattlefieldCards=GameHelper.playerBattlefieldCards local playerLeaderStats=playerLeaderCard.stats if not self.currentTurnMoveList then self.currentTurnMoveList=self:AssessMoves(aiHandCards,aiLeaderCard,aiBattlefieldCards,playerLeaderCard,playerBattlefieldCards,0) Logger:Debug("NORMAL: GENERATED MOVES:"..(#self.currentTurnMoveList),glMsgType.AI) foreach(self.currentTurnMoveList,function(move) Logger:Debug(" FINAL WEIGHT:"..move.id..(move.data.executingCard and (";"..move.data.executingCard.id) or "")..((move.data.targetCard and move.data.targetCard.id) and ";"..move.data.targetCard.id or "")..";scored:"..move.score,glMsgType.AI) end) end if self.styleOfPlay==0 then --general style of play, just does what AssessMoves returned as best in order if self:ProcessTurnSimple(deltaTime,self.currentTurnMoveList) then Logger:Debug(" executed move, generating new move set",glMsgType.AI) self.currentTurnMoveList=nil else end else end end function AIHelper:ProcessTurnSimple(deltaTime,moves) local aiHandCards=GameHelper.enemyHandCards local aiLeaderCard=GameHelper.enemyLeaderCard local aiLeaderStats=aiLeaderCard.stats local aiBattlefieldCards=GameHelper.enemyBattlefieldCards local playerLeaderCard=GameHelper.playerLeaderCard local playerBattlefieldCards=GameHelper.playerBattlefieldCards local playerLeaderStats=playerLeaderCard.stats local aiLeaderManaMax = aiLeaderStats.manaCount.max AIHelper.aiTimeForTurnInSecsCur=20--math.round(AIHelper.aiTimeForTurnInSecsBase + (aiLeaderManaMax/1.5),1) local turnFinished=AIHelper.aiTurnTimeCur>=AIHelper.aiTimeForTurnInSecsCur local canExecuteMove=not turnFinished and AIHelper.aiTurnTimeCur>=AIHelper.aiTurnTimeOfNextAction local finishedMove=false if GameHelper.tutorialPhase==45 or GameHelper.tutorialPhase==46 then --so unit doesnt attack before player reads tutorial return true end if string.find(AIHelper.aiCurrentMoveDesc,"FATIQUE") then --do nothing to allow player to perceive fatique else local tries=10 local aiFinished=false while (not finishedMove and not turnFinished and tries>0 and not aiFinished) do if canExecuteMove then local move move=table.remove(moves,1) if move then Logger:Debug("EXECUTING MOVE:"..move.id,glMsgType.AI) if move.id==self.movesEnum.SUMMON_UNIT then self:SetMoveDesc("Summoning Unit") finishedMove=self:SummonUnit(move.data.executingCard,aiLeaderStats) self.doneMoveThisTurn=true self.summonedThisTurn=true if GameHelper.tutorialPhase>0 and GameHelper.tutorialPhase==44 then GameHelper.tutorialPhase=45 local tutFunc1=function(ref) glEndTurnButton:visible(false) end AsyncQueueLogicHelper:AddToQueue( function(data) glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc1,{"Watch out for this enemy unit!","^14It has two new TAGS: DASH & VENOM.","Hover your mouse over the new unit","to learn about those tags!","","I will pause the game for you till then."}) end,{},1.5) end elseif move.id==self.movesEnum.ATTACK_WITH_UNIT or move.id==self.movesEnum.ATTACK_WITH_LEADER then self:SetMoveDesc("Thinking about attacking Player") finishedMove=self:AttackWithUnit(move.data.executingCard,move.data.targetCard) elseif move.id==self.movesEnum.CAST_SPELL then self:SetMoveDesc("Thinking about casting Spell") finishedMove=self:CastSpell(move.data.executingCard,move.data.targetCard) elseif move.id==self.movesEnum.DO_NOTHING then local str="Thinking" for i=1,AIHelper.doNothingCounter do str=str.." about thinking" end AIHelper.doNothingCounter=AIHelper.doNothingCounter+1 AIHelper:SetMoveDesc(str) finishedMove=true aiFinished=true end if not finishedMove then Logger:Debug("COULDNT EXECUTE MOVE:"..move.id,glMsgType.AI) end else aiFinished=true end if aiFinished then self:SetMoveDesc("Thinking about thinking about thinking") Logger:Debug("SIMPLE: NO MORE MOVES",glMsgType.AI) turnFinished=true end Logger:Debug("SIMPLE: finished move("..math.round(AIHelper.aiTurnTimeCur,2).."/"..math.round(AIHelper.aiTurnTimeOfNextAction,2)..")",glMsgType.AI) AIHelper.aiTurnTimeOfNextAction=AIHelper.aiTurnTimeOfNextAction+AIHelper.aiTimeBetweenActionsInSecs canExecuteMove=false end tries=tries-1 end if turnFinished then if not self.turnFinished then Logger:Debug("SIMPLE: FINISHED TURN ("..AIHelper.aiTurnTimeCur..")",glMsgType.AI) self.turnFinished=true SfxHelper:PlaySFX(glSFXNewTurnData.id,glSFXNewTurnData.noteDef,-1) AsyncQueueLogicHelper:AddToQueue(function(data) GameHelper:EndTurn() end,{},0.5) end end if AIHelper.aiDelayBeforeTurn>0 then AIHelper.aiDelayBeforeTurn=AIHelper.aiDelayBeforeTurn-deltaTime else if not AIHelper.stopUpdatingAI then AIHelper.aiTurnTimeCur=AIHelper.aiTurnTimeCur+deltaTime end end end return finishedMove or turnFinished end function AIHelper:SetMoveDesc(str) if self.aiCurrentMoveDesc~=str then self.aiLastMoveDesc=self.aiCurrentMoveDesc end self.aiCurrentMoveDesc=str end function AIHelper:CastSpell(spellToCast,targetCard) local cardN=-1 foreach(GameHelper.enemyHandCards,function(card,id) if card==spellToCast then cardN=id end end) Logger:Trace("BASE: trying to cast spell:"..spellToCast.id.." at "..targetCard.id,glMsgType.AI) --summon unit local leaderStats=GameHelper.enemyLeaderCard.stats if cardN>0 then local card=table.remove(GameHelper.enemyHandCards,cardN) GameHelper.enemyLeaderCard:SpendMana(card.stats.manaCost.cur) -- ai cards have no gui, so we need put coordinates for FXs! card.cardGUI={x=glEnemyLeaderCardGUI.x,w=glEnemyLeaderCardGUI.w,y=glEnemyLeaderCardGUI.y,h=glEnemyLeaderCardGUI.w,getCenterX=function(ref) return ref.x+ref.w/2 end,getCenterY=function(ref) return ref.y+ref.h/2 end,getRightX=function(ref) return ref.x+ref.w end,getDownY=function(ref) return ref.y+ref.h end} self:SetMoveDesc("Casting spell "..card.id.." at "..targetCard.id) local oldTargetCard=targetCard:DeepCopy(true) if GameHelper:CastSpellAction(card,card.cardGUI,targetCard,targetCard.cardGUI,false) then if targetCard.cardGUI then GUIHelper:FlashControlBorderForTime(targetCard.cardGUI,glGUIFrameStyleActiveWarningCard,2) GUIHelper:ShowActionAIDoneToPlayer(card,oldTargetCard,"CASTED SPELL ON",card,targetCard) end self.doneMoveThisTurn=true self.castedThisTurn=true Logger:Debug("BASE: casted:"..card.id.." from N:"..cardN,glMsgType.AI) return true else Logger:Debug("BASE: couldn't cast:"..card.id.." from N:"..cardN,glMsgType.AI) return false end end end function AIHelper:SummonUnit(cardFromHand,leaderStats,pos) local cardN=-1 foreach(GameHelper.enemyHandCards,function(card,id) if card==cardFromHand then cardN=id end end) Logger:Trace("BASE: trying to summon unit",glMsgType.AI) --summon unit if cardN>0 then local card=table.remove(GameHelper.enemyHandCards,cardN) GameHelper.enemyLeaderCard:SpendMana(card.stats.manaCost.cur) local n=pos and pos or #GameHelper.enemyBattlefieldCards+1 self:SetMoveDesc("Summoning Unit "..card.id.." at pos "..n) if GameHelper:SummonUnitOntoBattlefield(card,n,false) then Logger:Debug("BASE: summoned:"..card.id.." at:"..n,glMsgType.AI) if card.cardGUI then GUIHelper:FlashControlBorderForTime(card.cardGUI,glGUIFrameStyleActiveWarningCard,2) GUIHelper:ShowActionAIDoneToPlayer(nil,card,"SUMMONED UNIT",nil,card) end return true else Logger:Debug("BASE: couldn't summon:"..card.id.." at:"..n,glMsgType.AI) return false end end end function AIHelper:AttackWithUnit(unitToAttackWith,unitAttacked) Logger:Trace("BASE: trying to attack:"..unitAttacked.id..";with:"..unitToAttackWith.id,glMsgType.AI) local attacked=false local additionalCheck= unitAttacked:CanBeAttacked(GameHelper.playerBattlefieldCards,unitToAttackWith) if additionalCheck then GameHelper.currentGameState=glGameStates.UNIT_ATTACK_UNIT local canAtk=unitToAttackWith:CanExecuteAttack() local hp=unitAttacked.stats.hp.cur if canAtk and hp>0 then self.doneMoveThisTurn=true self.attackedThisTurn=true self:SetMoveDesc("Attacking "..unitAttacked.id.." with "..unitToAttackWith.id,glMsgType.AI) GUIHelper:FlashControlBorderForTime(unitToAttackWith.cardGUI,glGUIFrameStyleActiveWarningCard,1.2) local oldCard1=unitToAttackWith:DeepCopy(true) local oldCard2=unitAttacked:DeepCopy(true) attacked=GameHelper:ExecuteAttackAction(unitToAttackWith,unitToAttackWith.cardGUI,unitAttacked,unitAttacked.cardGUI) Logger:Debug("BASE: attacked:"..(attacked and "TRUE" or "FALSE").." id:"..unitAttacked.id.." with:"..unitToAttackWith.id,glMsgType.AI) GUIHelper:ShowActionAIDoneToPlayer(unitToAttackWith,unitAttacked,"ATTACKED UNIT",oldCard1,oldCard2) else Logger:Debug("BASE: unit can't execute the attack:"..(canAtk and 1 or 0)..";"..hp,glMsgType.AI) end else Logger:Debug("BASE: unit can't be attacked",glMsgType.AI) end return attacked end -- AchievementsHelper CLASS AchievementsHelper = {} AchievementsHelper.__index=AchievementsHelper AchievementsHelper.id="AchievementsHelper" -- STATEHELPER CLASS --is data class current turn and has methods to storing/restoring/cleaning/work on current turn data StateHelper = {} StateHelper.__index=StateHelper StateHelper.id="StateHelper" function StateHelper:UpdateNonPlayingState(deltaTime,selCardGUI1st,cardObj1st,statsCard1st,selCardGUI2nd,cardObj2nd,statsCard2nd) local gh=GameHelper if StateHelper.gameModeStarted then --choose cards and initialize game glRerollStartingCardsGUI:hide() if not gh.finishedChoosingCards then StateHelper:HandleChoosingStartingCardsGUILogic(StateHelper.cardObj2nd) else local n=StateHelper:CleanStateAfterChoosingStartingCardsAndReturnNumberOfCardsToRedraw() for i=1,n do AsyncQueueLogicHelper:AddToQueue(function(data) gh:ExecuteDrawCard(true) end,{},0+0.2*i) end local len=#GameHelper.playerHandCards for i=0,len-1 do ParticleHelper:CreateSummoningCardFX(i*32+24,134) ParticleHelper:CreateSummoningCardFX(i*32+20,132) end end else if gh.matchFinished then local playerLeaderStats=gh.playerLeaderCard.stats local enemyLeaderStats=gh.enemyLeaderCard.stats local startReIniting=false --show artifact if specific level is reached local artifactRound=((#gh.playerLeaderCard.artifactsIDList)0 then StateHelper.gameStarted=true gh.playerChoosenDeckID="DECK000" gh.enemyChoosenDeckID="DECK000" gh:InitDeckAndHandFromID(GameHelper.playerChoosenDeckID,true) gh:InitMatchStart() end --choose game mode and starting leader if not gh.finishedCreatingLeader then else end --choose starting deck if not gh.finishedChoosingDeck then else gh.playerChoosenDeck=true gh:InitDeckAndHandFromID(gh.playerChoosenDeckID,true) --add selected tags in leader creation foreach(glCreateLeaderCardTagsGUI.tagsGUI,function(tagGUI) if tagGUI.clicked and tagGUI.tagObj then local tag=deepcopy_old(tagGUI.tagObj) GameHelper.playerLeaderCard:InsertTag(tag) if tag.funcAfterInit then tag:funcAfterInit(GameHelper.playerLeaderCard) end end end) gh.playerLeaderFormula=GameHelper.playerLeaderCard:DeepCopy() gh:PreInitAndShowSummaryScreen() end end end end function StateHelper:UpdatePlayingState(deltaTime,selCardGUI1st,cardObj1st,statsCard1st,selCardGUI2nd,cardObj2nd,statsCard2nd) local gameFinished=(not GameHelper.playerLeaderCard or GameHelper.playerLeaderCard.isDeleted) or (not GameHelper.enemyLeaderCard or GameHelper.enemyLeaderCard.isDeleted) or GameHelper.forcePlayerLosing if gameFinished then if TutorialHelper:CheckIfTutorialIsActive() then local ret=TutorialHelper:CheckForEndOfTheMatch() if ret then return end else GameHelper.usedArtifactDoubler=false if not GameHelper.playerLeaderCard or GameHelper.playerLeaderCard.isDeleted or GameHelper.forcePlayerLosing then if GameHelper.finishingMatch then return end GameHelper:EndMatch(false,true) return end if not GameHelper.enemyLeaderCard or GameHelper.enemyLeaderCard.isDeleted then if GameHelper.finishingMatch then return end GameHelper:EndMatch(true,true) return end end end if GameHelper.isPlayerTurn then GameHelper:ParseAndProcessPlayerTurnForGUI(deltaTime,selCardGUI1st,cardObj1st,statsCard1st,StateHelper.selCardGUI2nd,StateHelper.cardObj2nd,statsCard2nd) GameHelper:ProcessPlayerTurnLogic(deltaTime,selCardGUI1st,cardObj1st,statsCard1st,StateHelper.selCardGUI2nd,StateHelper.cardObj2nd,statsCard2nd) else --TODO: make ai turn use process player turn where you push leader object and ai will just add own stuff when needed via events! GameHelper:ProcessAITurn(deltaTime) end end function StateHelper:OpenOptionWindowAndUnclick() --TODO: generate procedural method for every window like this - package this into data array with those values? if not glGUIFrameGameOptions then GUICreator:CreateGameOptionsScreen() end GUIHelper.gameOptionsOpened=true glGUIFrameGameOptions:allToFront() glGUIFrameGameOptions:show() GUIHelper.gameOptionsButtonClicked=false end function StateHelper:CleanStateAfterChoosingStartingCardsAndReturnNumberOfCardsToRedraw() local gh=GameHelper local n=0 local len=#GUIHelper.playerHandCards for i=len,1,-1 do local cardGUI=GUIHelper.playerHandCards[i] if cardGUI.drawX and cardGUI.cardObj then local card=table.remove(gh.playerHandCards,cardGUI.pos) table.insert(gh.playerDeckCards,card) n=n+1 end cardGUI.drawX=false end GUICreator:RemoveRedrawingStartingCardsScreen() gh.playerChoosenCards=true return n end function StateHelper:HandleChoosingStartingCardsGUILogic() local gh=GameHelper if table.contains(gh.playerLeaderCard.artifactsIDList,"SELECT_STARTING_CARDS") then glRerollStartingCardsGUI:show() else glRerollStartingCardsGUI:hide() end if gh.RerollStartingCards then gh.RerollStartingCards=false local len=#GUIHelper.playerHandCards local rN=0 for i=len,1,-1 do local cardGUI=GUIHelper.playerHandCards[i] if cardGUI.drawX and cardGUI.cardObj then local card=table.remove(gh.playerHandCards,cardGUI.pos) table.insert(gh.playerDeckCards,card) rN=rN+1 end cardGUI.drawX=false end for j=1,rN do local card=table.insert(gh.playerHandCards,table.remove(gh.playerDeckCards,1)) end end local i=1 if StateHelper.cardObj2nd then StateHelper.selCardGUI2nd.drawX=not StateHelper.selCardGUI2nd.drawX SfxHelper:PlaySFX((StateHelper.selCardGUI2nd.drawX and glSFXConfirmGUIData or glSFXCancelGUIData).id,glSFXConfirmGUIData.noteDef) StateHelper.cardObj2nd=nil StateHelper.selCardGUI2nd=nil gh.cardGUIElemSelected=nil end end function StateHelper:ShowTAGTooltipForHoveredCard() if glDebugMode then local cardObj = GUIHelper.controlHoveredOver.cardObj if cardObj then foreach(cardObj.stats,function(stat) table.insert(glGUIFrameMouseTooltip.textArray,{text=stat.name..":"..(stat.cur and (stat.cur.."/"..stat.max) or ""),color=15,smallFont=true}) end) end else for id=1,(StateHelper.cardHoveredGUI.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=StateHelper.cardObjHovered:GetTagByPos(id) if tag then if tag.data.split then if tag.data.split[1]=="SUMMON" then local cID=tag.data.split[2] local card2nd=GameHelper.allCards[cID] if card2nd then glGUIFrameMouseCard2ndPreview.cardObj=card2nd end end end table.insert(glGUIFrameMouseTooltip.textArray,{prefixSpr=tag.spr,text=tag:genNameAsStr(StateHelper.cardObjHovered),color=14,smallFont=false}) local desc=tag:genDesc(StateHelper.cardObjHovered) --hack because of bug introduced with genDesc?? for n=0,(#desc) do local d=desc[n] if d then table.insert(glGUIFrameMouseTooltip.textArray,{text=d.str,color=d.c,smallFont=true}) end end if tag.name=="VENOM" and GameHelper.tutorialPhase==45 then GameHelper.tutorialPhase=46 local tutFunc1=function(ref) GameHelper.tutorialPhase=47 end AsyncQueueLogicHelper:AddToQueue(function() glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc1,{"^14Every unit can have up to 3 TAGS active","^14while leader units can have up to 6 TAGS.","","^15Now let's end up this turn.",})end,{},1) end if GameHelper.tutorialPhase==43 then GameHelper.tutorialPhase=44 local tutFunc1=function(ref) GameHelper.playerLeaderCard.stats.manaCount.cur=2 GameHelper.playerLeaderCard.stats.manaVisualCount.cur=2 glTutorialIsBlockingGUI=false end glTutorialIsBlockingGUI=true AsyncQueueLogicHelper:AddToQueue(function() glEndTurnButton:visible(true) glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc1,{"^14Those powers are called TAGS.","^14TAGS allow units to change, ignore","^14or even add new rules.","","With this, your new unit will stop","the enemy from attacking your leader.","^15Use those units to win this fight!",})end,{},1) end if GameHelper.tutorialPhase==48 and tag.name=="ARMORBUFF_TUTORIAL" then local tutFunc1=function(ref) glTutorialIsBlockingGUI=false GameHelper.playerLeaderCard.stats.manaCount.cur=6 GameHelper.playerLeaderCard.stats.manaVisualCount.cur=6 glEndTurnButton:visible(false) end local tutFunc0=function(ref) AsyncQueueLogicHelper:AddToQueue(function() glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc1,{"^14Normally you can cast spell","on any unit you want!", "^14but for this tutorial try it on","one of the units with DISTRACT tag",}) end,{},1) end GameHelper.tutorialPhase=49 glTutorialIsBlockingGUI=true AsyncQueueLogicHelper:AddToQueue(function() glEndTurnButton:visible(false) glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc0,{"^14SPELLS can have up to 3 TAGS","^14That will be 'used' on casting","^14Power of the spell comes from SPELLPWR","^14Value found next to blue staff icon,","below mana cost value."}) end,{},4) end end end end end function StateHelper:PassTimeOfMouseHoveringOnCard(deltaTime) GameHelper.cardGUIHoveredTime=((GameHelper.cardGUIElemHoveredOver and StateHelper.lastHooveredCard==GameHelper.cardGUIElemHoveredOver) and (GameHelper.cardGUIHoveredTime+deltaTime) or 0) GUIHelper.controlHoveredTime=((GUIHelper.controlHoveredOver and StateHelper.lastHooveredControl==GUIHelper.controlHoveredOver) and (GUIHelper.controlHoveredTime+deltaTime) or 0) end function StateHelper:ProcessTooltipsAndCardHoverGUI() local isInTutorial=GameHelper.tutorialPhase>0 local showsCardBeforeTag=GameHelper.showFullCardPreviewInBattle>0 or (GameHelper.ShowingInventoryScreen) if StateHelper.cardHoveredGUI then StateHelper.cardObjHovered=StateHelper.cardHoveredGUI.cardObj if StateHelper.cardHoveredGUI.isHandCard then StateHelper.cardHoveredGUI:toFront(ticuare.hz+3) if StateHelper.cardHoveredGUI~=GameHelper.cardGUIElemSelected1st then StateHelper.cardHoveredGUI.y=((GameHelper.playerChoosenCards and (not StateHelper.cardGUI1st)) and StateHelper.cardHoveredGUI.y-40 or StateHelper.cardHoveredGUI.y) end if not isInTutorial or GameHelper.tutorialPhase>40 then if GameHelper.cardGUIHoveredTime>GameHelper.delayBeforeShowingTooltips then StateHelper:ShowTAGTooltipForHoveredCard() end end else if (GameHelper.cardGUIHoveredTime>GameHelper.delayBeforeShowingFullCard) and StateHelper.cardHoveredGUI.cardObj then if not GameHelper.cardGUIElemSelected1st then --because player is looking at attack preview if not isInTutorial or GameHelper.tutorialPhase>40 then -- not in tutorial where we dont need this if GameHelper.cardGUIHoveredTime>((showsCardBeforeTag and GameHelper.delayBeforeShowingFullCard or 0)+GameHelper.delayBeforeShowingTooltips) then StateHelper:ShowTAGTooltipForHoveredCard() end end glGUIFrameMouseCardPreview.cardObj=StateHelper.cardHoveredGUI.cardObj end glGUIFrameMouseCardPreview.simulatedCardObj=GameHelper.allCards[StateHelper.cardHoveredGUI.cardObj.id] else StateHelper:ClearHoverCardsGUIFrames() end end else StateHelper:ClearHoverCardsGUIFrames() end if StateHelper.cardGUI1st and StateHelper.cardGUI1st.isHandCard then StateHelper.cardGUI1st.y=StateHelper.cardGUI1st.y-10 end end function StateHelper:ProcessBattlefieldGUI() glPlayerLeaderCardGUI.cardObj=GameHelper.playerLeaderCard GameHelper.playerLeaderCard.cardGUI=glPlayerLeaderCardGUI glEnemyLeaderCardGUI.cardObj=GameHelper.enemyLeaderCard GameHelper.enemyLeaderCard.cardGUI=glEnemyLeaderCardGUI local i=0 foreach(GUIHelper.playerHandCards,function(cardGUI) local cardObj=GameHelper.playerHandCards[i+1] cardGUI:visible(cardObj~=nil and not GameHelper.ShowedEndGameSummary) cardGUI:active(cardObj~=nil and not GameHelper.ShowedEndGameSummary) local hadCardObj=cardGUI.cardObj and (cardObj and cardObj.cardGUI or false) if cardObj then cardGUI.cardObj=cardObj cardObj.cardGUI=cardGUI cardGUI:toFront(ticuare.hz) if (StateHelper.gameModeStarted and not GameHelper.ShowingInventoryScreen) then if StateHelper.gameStarted then cardGUI.x=cardGUI.origX cardGUI.y=glScreenPixelHeight-22+(i%2==1 and 1 or -5) else local cardsLen=(#GameHelper.playerHandCards) local cx=0 local cardSize=42 local offset=2 if cardsLen>5 then offset = cardsLen==6 and 3 or offset cardSize=cardsLen==6 and 38 or 32 else if glChooseStaringCardsGUI then cx=glChooseStaringCardsGUI.w-4 cx=cx-cardsLen*cardSize cx=cx/2 end end if glChooseStaringCardsGUI then cardGUI.x=glChooseStaringCardsGUI.x+offset+cx+i*cardSize cardGUI.y=glChooseStaringCardsGUI.y+11 end end else cardGUI.x=cardGUI.origX cardGUI.y=glScreenPixelHeight+200 end end if (not hadCardObj) and cardObj then Logger:Info("USING THIS FOR SOME REASON!!!!",glMsgType.GUI) AsyncQueueLogicHelper:AddToQueue(function(data) SfxHelper:PlaySFX(glSFXDrawCardData.id,glSFXDrawCardData.noteDef) if cardGUI then ParticleHelper:CreateSummoningCardFX(cardGUI:getCenterX(),(gameStarted and glScreenPixelHeight-2 or cardGUI:getDownY())) end end,{},gameStarted and 0.1 or 1) end if cardGUI.border==glGUIFrameStyleActiveOKCard.border then GameHelper.haveStuffToDo=true --TODO: this should be set by gamelogic helper, not gui end i=i+1 end) i=0 foreach(GUIHelper.playerHandCards,function(cardGUI) local cardObj=GameHelper.playerHandCards[i+1] if cardObj then if i%2==1 then cardGUI:toFront(ticuare.hz) else cardGUI:toFront(ticuare.hz-1) end end i=i+1 end) i=1 foreach(GUIHelper.playerBattlefieldCards,function(cardGUI) local battlefieldCard=GameHelper.playerBattlefieldCards[i] cardGUI.cardObj=battlefieldCard if battlefieldCard then battlefieldCard.cardGUI=cardGUI end if cardGUI.border==glGUIFrameStyleActiveOKCard.border then GameHelper.haveStuffToDo=true end i=i+1 end) i=1 foreach(GUIHelper.enemyBattlefieldCards,function(cardGUI) local battlefieldCard=GameHelper.enemyBattlefieldCards[i] cardGUI.cardObj=battlefieldCard if battlefieldCard then battlefieldCard.cardGUI=cardGUI end i=i+1 end) end function StateHelper:CleanPlayerMouseSelection() GameHelper.cardGUIElemHoveredOver=nil GUIHelper.controlHoveredOver=nil GUIHelper.controlClicked=nil GameHelper.cardGUIElemSelected=nil GameHelper.cardGUIElemSelected1st=nil end function StateHelper:ClearHoverCardsGUIFrames() glGUIFrameMouseCard2ndPreview.cardObj=nil glGUIFrameMouseCardPreview.setMouseCoords=true glGUIFrameMouseCardPreview.cardObj=nil glGUIFrameMouseCardPreview.simulatedCardObj=nil end -- GAMEUPDATE CLASS --is method class that has all methods related to updating game BaseUpdate = {} BaseUpdate.__index=BaseUpdate BaseUpdate.id="BaseUpdate" function BaseUpdate:UpdateBaseVars() glFramesCounter=glFramesCounter+1 glFrame60FramesCounter=(glFrame60FramesCounter+1)%60 glFrameEveryOther=not glFrameEveryOther glFrame10thFrame=glFrame60FramesCounter%10==0 glFrame15thFrame=glFrame60FramesCounter%15==0 glFrame20thFrame=glFrame60FramesCounter%20==0 glFrame25thFrame=glFrame60FramesCounter%25==0 glFrame30thFrame=glFrame60FramesCounter%30==0 if glFrame10thFrame then glPulseStatusForEvery10thFrame=not glPulseStatusForEvery10thFrame end if glFrame15thFrame then glPulseStatusForEvery15thFrame=not glPulseStatusForEvery15thFrame end if glFrame30thFrame then glPulseStatusForEvery30thFrame=not glPulseStatusForEvery30thFrame end end function BaseUpdate:GameTurnGUIClear() GUIHelper.controlHoveredOver=nil GameHelper.cardGUIElemHoveredOver=nil GUIHelper.controlClickHolding=nil GameHelper.cardGUIElemClickHolding=nil GUIHelper.endTurnButtonClicked=false glGUIFrameMouseTooltip.textArray={} GUIHelper.notUpdateAIActionEvents=false end function BaseUpdate:SetMouseGlobalVars(up,down,left,right,a,b,x,y) glButtons.up=up glButtons.down=down glButtons.left=left glButtons.right=right glButtons.a=a glButtons.b=b glButtons.x=x glButtons.y=y local mx,my,lmd,mmd,rmd=mouse() glMouse.last3rdX=glMouse.last2ndX glMouse.last3rdY=glMouse.last2ndY glMouse.last2ndX=glMouse.lastX glMouse.last2ndY=glMouse.lastY glMouse.lastX=glMouse.x glMouse.lastY=glMouse.y glMouse.lastLMD=glMouse.lPressed glMouse.realLastX=glMouse.realX glMouse.realLastY=glMouse.realY glMouse.realX=mx glMouse.realY=my end function BaseUpdate:SetTypeOfControls(clickedAnyKey) if (glMouse.realX~=glMouse.realLastX) or (glMouse.realY~=glMouse.realLastY) then GameHelper.controlScheme=GameHelper.touchControls and 2 or 1 GameHelper.pointerControls=true end end function BaseUpdate:UpdateControlsForThisFrame(mx,my,lmd,mmd,rmd) if GameHelper.touchControls then if lmd then glMouse.touchLastPosX=nil glMouse.touchLastPosY=nil elseif glMouse.touchLastPosX and glMouse.touchLastPosX==mx and glMouse.touchLastPosY==my then mx=-10 my=-10 else if (glMouse.lastLMD==lmd) and (mx==glMouse.lastX and mx==glMouse.last2ndX and mx==glMouse.last3rdX) and (my==glMouse.lastY and my==glMouse.last2ndY and my==glMouse.last3rdY) then glMouse.touchLastPosX=mx glMouse.touchLastPosY=my mx=-10 my=-10 glMouse.last3rdX=mx glMouse.last3rdY=my glMouse.last2ndX=mx glMouse.last2ndY=my glMouse.lastX=mx glMouse.lastY=my else glMouse.touchLastPosX=nil glMouse.touchLastPosY=nil end end end glMouse.x=mx glMouse.y=my glMouse.lPressed=lmd glMouse.mPressed=mmd glMouse.rPressed=rmd if lmd then ParticleHelper:CreateMouseClickWithNoInteractionFX(mx,my,0) end end -- GAMEHELPER CLASS --is data class about game data that isnt current turn specific (look STATEHELPER) and has methods relate to game logic GameHelper = {} GameHelper.__index=GameHelper GameHelper.id="GameHelper" function GameHelper:ExecuteDrawCard(forPlayer,cardPos,deck) cardPos= cardPos and cardPos or 1 deck = deck and deck or (forPlayer and GameHelper.playerDeckCards or GameHelper.enemyDeckCards) local leaderObj=forPlayer and GameHelper.playerLeaderCard or GameHelper.enemyLeaderCard local cardDrawnObj=0 if forPlayer then --TODO: remove duplication between player and ai if #GameHelper.playerHandCards<7 then local card if #deck>0 then if deck[cardPos] then card=table.remove(deck,cardPos) ParticleHelper:CreateSummoningCardFX((#GameHelper.playerHandCards)*32+24,134) ParticleHelper:CreateSummoningCardFX((#GameHelper.playerHandCards)*32+20,132) end else card=GameHelper.allCards.FATIQUE:DeepCopy() card.stats.attack.cur=GameHelper.playerNumOfTurnsWithoutCards+1 GameHelper.playerNumOfTurnsWithoutCards=GameHelper.playerNumOfTurnsWithoutCards+1 AsyncQueueLogicHelper:AddToQueue(function(data) if GameHelper.playerHandCards then ParticleHelper:CreateDeathFX((#GameHelper.playerHandCards)*32,130,0) end local cardObj=data.cardObj local cardGUI=data.cardGUI if GameHelper.tutorialPhase>0 and GameHelper.tutorialPhase==45 then GameHelper.tutorialPhase=36 AsyncQueueLogicHelper:AddToQueue(function(data) glTutorialDialog=GUIHelper:CreateTutorialDialog(function(ref) AsyncQueueLogicHelper:AddToQueue(function(data) table.remove(GameHelper.playerHandCards,#GameHelper.playerHandCards) cardObj.stats.hp:sub(data.card.stats.attack.cur) GUIHelper:DrawChangeIndicator(GUIHelper.playerLeaderCard,"HP",-data.card.stats.attack.cur,0) if GameHelper.playerHandCards then ParticleHelper:CreateDeathFX((#GameHelper.playerHandCards)*32,130,0) end SfxHelper:PlaySFX(glSFXHPDamageData.id,glSFXHPDamageData.noteDef) if not simulateOnly then GUIHelper.ShakeFrameControl(cardGUI,4,0.2,0) end if not cardObj.stats.hp:aboveMin() then glTutorialDialog=GUIHelper:CreateTutorialDialog(function(ref) GameHelper.tutorialPhase=38 end,{"Uh oh! Oh uh!","It looks like you would die from this card draw!","Let me reset this tutorial for you","Next time try to finish fight","before FATIQUE gets you!"}) end end,{card=card,cardGUI=GUIHelper.playerLeaderCard,cardObj=GameHelper.playerLeaderCard},5) end,{"Uh oh!","Looks like you are out of cards!","Which means you are in FATIQUE state.","^14Every player that tries to draw card","^14with none in the deck left will have","^14their leader unit HP damaged.","^14That DMG increases with every card drawn."})end,{},2) else table.remove(GameHelper.playerHandCards,#GameHelper.playerHandCards) cardObj.stats.hp:sub(data.card.stats.attack.cur) SfxHelper:PlaySFX(glSFXHPDamageData.id,glSFXHPDamageData.noteDef) if not simulateOnly then GUIHelper.ShakeFrameControl(cardGUI,4,0.2,0) end if not cardObj.stats.hp:aboveMin() then EventHelper:ExecuteEvent(glEventTypes.UNIT_DIED,"KILL_CARD_DRAW",simulateOnly,{cardObj=cardObj,initingObj=cardObj,typeOfDeath=glUnitDeathTypes.CARD_DRAW}) GameHelper:DestroyUnit(cardObj,cardGUI,0) end end end,{card=card,cardGUI=GUIHelper.playerLeaderCard,cardObj=GameHelper.playerLeaderCard},2+0.5*(2-GameHelper.animationSpeed)) end cardDrawnObj=card if card then table.insert(GameHelper.playerHandCards,card) end else return false end else if #GameHelper.enemyHandCards<7 then AIHelper:SetMoveDesc("Drawing card") local card local dmgCard=false if #deck>0 then if deck[cardPos] then card=table.remove(deck,1) end else dmgCard=true AIHelper:SetMoveDesc("Getting DMG from FATIQUE") card=GameHelper.allCards.FATIQUE:DeepCopy() --TODO: move this and player one to stats? card.stats.attack.cur=GameHelper.enemyNumOfTurnsWithoutCards+1 GameHelper.enemyNumOfTurnsWithoutCards=GameHelper.enemyNumOfTurnsWithoutCards+1 AsyncQueueLogicHelper:AddToQueue(function(data) ParticleHelper:CreateDeathFX(32,0,0) table.remove(GameHelper.enemyHandCards,#GameHelper.enemyHandCards) local cardObj=data.cardObj local cardGUI=data.cardGUI cardObj.stats.hp:sub(data.card.stats.attack.cur) GUIHelper:DrawChangeIndicator(GUIHelper.enemyLeaderCard,"HP",-data.card.stats.attack.cur,0) if not simulateOnly then GUIHelper.ShakeFrameControl(cardGUI,4,0.2,0) end if not cardObj.stats.hp:aboveMin() then EventHelper:ExecuteEvent(glEventTypes.UNIT_DIED,"KILL_CARD_DRAW",simulateOnly,{cardObj=cardObj,initingObj=cardObj,typeOfDeath=glUnitDeathTypes.CARD_DRAW}) GameHelper:DestroyUnit(cardObj,cardGUI,0) end AsyncQueueLogicHelper:AddToQueue(function(data) AIHelper:SetMoveDesc("Thinking") end,{},1) end,{card=card,cardGUI=GUIHelper.enemyLeaderCard,cardObj=GameHelper.enemyLeaderCard},2+0.5*(2-GameHelper.animationSpeed)) end cardDrawnObj=card if card then if glEnemyToolbarCards then GUIHelper:FlashControlBorderForTime(glEnemyToolbarCards,glGUIFrameStyleActiveWarningCard,1) ParticleHelper:CreateSummoningCardFX(glEnemyToolbarCards.x+glEnemyToolbarCards.w-40,7) end table.insert(GameHelper.enemyHandCards,card) AsyncQueueLogicHelper:AddToQueue(function(data) SfxHelper:PlaySFX(glSFXDrawCardData.id,glSFXDrawCardData.noteDef) end,{},0.1) end local hasCardsVisibleArtifact=table.contains(GameHelper.playerLeaderCard.artifactsIDList,"ENEMY_CARDS_VISIBLE") GUIHelper:ShowActionAIDoneToPlayer(nil,hasCardsVisibleArtifact and card or nil,dmgCard and "NO CARDS LEFT" or "DRAWS CARD",nil,nil) else return false end end --TODO: pass what is initing this event (to ExecuteDrawCard) EventHelper:ExecuteEvent(glEventTypes.CARD_DRAWN,self,false,{cardObj=cardDrawnObj,initingObj=leaderObj,cardsOnHandNum= #(forPlayer and GameHelper.playerHandCards or GameHelper.enemyHandCards),cardsLeftInDeckNum= #(forPlayer and GameHelper.playerDeckCards or GameHelper.enemyDeckCards)}) return true end function GameHelper:InitDeckAndHandFromID(deckID,isPlayer) local debug=false local deck=self:GenerateDeckFromID(deckID) if deck then deck=GameHelper:ShuffleDeck(deck) else Logger.ERROR((isPlayer and "PLAYER" or "ENEMY")..";Couldn't init deck:"..(deckID and deckID or "NIL"),glMsgType.GAME_LOGIC) return end if isPlayer then foreach(deck,function(card) if table.contains(GameHelper.playerLeaderCard.artifactsIDList,"CHEAPER_SPELLS") then if card.isSpell then card.stats.manaCost:sub(1) end end end) end local hand={} for i=1,RuleHelper.startHandSize+(table.contains((isPlayer and GameHelper.playerLeaderCard or GameHelper.enemyLeaderCard).artifactsIDList,"DRAW_2_MORE_CARDS") and 2 or 0) do local card=table.insert(hand,table.remove(deck,1)) end if isPlayer then GameHelper.playerDeckCards=deck GameHelper.playerHandCards=hand else GameHelper.enemyDeckCards=deck GameHelper.enemyHandCards=hand end Logger:Info((isPlayer and "PLAYER" or "ENEMY")..";Inited deck:"..deckID,glMsgType.GAME_LOGIC) --TODO: why this generates empty deck on specific occasions? EventHelper:ExecuteEvent(glEventTypes.DECK_CREATED,self,simulateOnly,{deck=deck,hand=hand,forPlayer=isPlayer}) return deck end function GameHelper:GenerateTemplateFromDeck(deck) local d={} if deckOrig then Logger:Trace("copying deck:"..(#deck),glMsgType.GAME_LOGIC) foreach(deck,function(card) if not card then return end table.insert(d,card.ID) i=i+1 end) else Logger:Debug("DECK WAS NIL!",glMsgType.GAME_LOGIC) end Logger:Debug("copied deck:"..(#d),glMsgType.GAME_LOGIC) return d end function GameHelper:GenerateDeckFromID(deckID) local deckOrig=GameHelper.allDeckTemplates[deckID] local deck={} if deckOrig then Logger:Trace("copying deck:"..deckID..";"..(#deckOrig),glMsgType.GAME_LOGIC) foreach(deckOrig,function(cardID) local cardTemp=GameHelper.allCards[cardID] if not cardTemp or cardTemp.turnedOff then return end local card1=cardTemp:DeepCopy() table.insert(deck,card1) i=i+1 end) if glDebugMode then --[[local cardTemp=GameHelper.allCards["A020"] local card1=cardTemp:DeepCopy() table.insert(deck,card1) card1=cardTemp:DeepCopy() table.insert(deck,card1) card1=cardTemp:DeepCopy() table.insert(deck,card1) card1=cardTemp:DeepCopy() table.insert(deck,card1) card1=cardTemp:DeepCopy() table.insert(deck,card1) card1=cardTemp:DeepCopy() cardTemp=GameHelper.allCards["A029"] card1=cardTemp:DeepCopy() table.insert(deck,card1) card1=cardTemp:DeepCopy() table.insert(deck,card1) card1=cardTemp:DeepCopy() table.insert(deck,card1) card1=cardTemp:DeepCopy() table.insert(deck,card1) card1=cardTemp:DeepCopy() table.insert(deck,card1) card1=cardTemp:DeepCopy() table.insert(deck,card1)]]-- end else Logger:Debug("DIDNT FOUND DECK BY ID:"..deckID,glMsgType.GAME_LOGIC) end Logger:Debug("copied deck:"..(#deck),glMsgType.GAME_LOGIC) return deck end function GameHelper:PreInitAndShowSummaryScreen() GameHelper.ShowedInventoryScreen=true GameHelper.ShowingInventoryScreen=true GameHelper.enemyLeaderCard.cardGUI=nil local ld=glDungeonRunEnemyLeaderList[GameHelper.gamesWon+1] Logger:Trace("Generated enemy Leader:"..ld.id..";with stats:"..ld.stats.attack.max..";"..ld.stats.hp.max..";"..ld.stats.armor.max..";tags:"..(#ld.tags),glMsgType.INIT_GAME) local enemyLeader=glDungeonRunEnemyLeaderList[GameHelper.gamesWon+1]:DeepCopy(true) Logger:Debug("Enemy Leader:"..enemyLeader.id..";with stats:"..enemyLeader.stats.attack.max..";"..enemyLeader.stats.hp.max..";"..enemyLeader.stats.armor.max..";tags:"..(#enemyLeader.tags),glMsgType.INIT_GAME) enemyLeaderStats=enemyLeader.stats GameHelper.enemyLeaderCard=enemyLeader local enemyLeaderStats=enemyLeader.stats enemyLeaderStats.hp:setToMax() enemyLeaderStats.armor:setToMax() enemyLeaderStats.attack:setToMax() enemyLeaderStats.manaCount.max=(table.contains(enemyLeader.artifactsIDList,"MORE_MANA") and 1 or 0) enemyLeader:RestoreMana(0,true) enemyLeaderStats.attacksAvail:setToMin() enemyLeader.cardGUI=GUIHelper.enemyLeaderCard GUIHelper.enemyLeaderCard.cardObj=enemyLeader GameHelper.enemyLeaderCard=enemyLeader EventHelper:ExecuteEvent(glEventTypes.LEADER_CREATED,self,simulateOnly,{cardObj=enemyLeader}) GameHelper:SetAIBasedOnGameProgress(GameHelper.gamesWon) GameHelper.enemyChoosenDeckID=glDungeonRunDeckList[GameHelper.gamesWon+1] GameHelper:InitDeckAndHandFromID(GameHelper.enemyChoosenDeckID,false) GameHelper.playerLeaderCard=GameHelper.playerLeaderFormula:DeepCopy() local playerLeader=GameHelper.playerLeaderCard local playerLeaderStats=playerLeader.stats playerLeaderStats=GameHelper:InitLeaderCardStatsTable(playerLeaderStats.hp.max,playerLeaderStats.armor.max,playerLeaderStats.attack.max) playerLeaderStats.hp:setToMax() playerLeaderStats.armor:setToMax() playerLeaderStats.attack:setToMax() playerLeaderStats.manaCount.max=(table.contains(playerLeader.artifactsIDList,"MORE_MANA") and 1 or 0) playerLeader:RestoreMana(0,true) playerLeaderStats.attacksAvail:setToMin() playerLeader.stats=playerLeaderStats GameHelper.playerLeaderCard=playerLeader EventHelper:ExecuteEvent(glEventTypes.LEADER_CREATED,self,simulateOnly,{cardObj=playerLeader}) local d=GameHelper:InitDeckAndHandFromID(GameHelper.playerChoosenDeckID,true) GameHelper:GenerateNewArtifactOptions(GameHelper.artifactsEncounterLvl) --TODO: move those to init betweenmatchesstate? GameHelper:GenerateNewBucketOptions() foreach(glStartGameModeFrameDeckGUI.cardControls,function(cardGUI) cardGUI:remove() end) glStartGameModeFrameDeckGUI.cardControls={} local i=0 local isInTutorial=GameHelper.tutorialPhase>0 if StateHelper.gameStarted and not isInTutorial then foreach(GameHelper.playerHandCards,function(cardObj) Logger:Trace("glStartGameModeFrameDeckGUI:"..glStartGameModeFrameDeckGUI.x..";"..glStartGameModeFrameDeckGUI.y..";"..glStartGameModeFrameDeckGUI.w..";"..glStartGameModeFrameDeckGUI.h,glMsgType.GUI) local cardGUI=GUIHelper:CreateGUIFrame("glStartGameModeFrameDeckGUI_card_"..i,glStartGameModeFrameDeckGUI.x+3,glStartGameModeFrameDeckGUI.y+10+i*9,glStartGameModeFrameDeckGUI.w-6,10,glBackgroundWithBorderGUIBlackStyle) cardGUI:addParent(glStartGameModeFrameDeckGUI) cardGUI:Content(function(ref,x,y) local cardObj=ref.cardObj if cardObj then print(cardObj.id,x+1,y+1,15) end end) table.insert(glStartGameModeFrameDeckGUI.cardControls,cardGUI) i=i+1 end) end local d={} foreach(GameHelper.allDeckTemplates[GameHelper.playerChoosenDeckID],function(cardID) table.insert(d,GameHelper.allCards[cardID]) end) table.sort(d,function(a,b) return a.stats.manaCost.cur0 and GameHelper.tutorialPhase<60 then glChooseStaringDeckGUI:hide() glCreateLeaderCardGUI:hide() else GUICreator:RemoveRedrawingStartingCardsScreen() AsyncQueueLogicHelper:AddToQueue(function(data) if not glChooseStaringCardsGUI then GUICreator:CreateRedrawingStartingCardsScreen() end glChooseStaringCardsGUI:show() if table.contains(playerLeader.artifactsIDList,"SELECT_STARTING_CARDS") then glRerollStartingCardsGUI:show() else glRerollStartingCardsGUI:hide() end end,{},1.5) glEndTurnButton:visible(false) end GUIHelper.gameOptionsButtonClicked=false GameHelper.turnCounter=1 GameHelper.allturnsCounter=1 GameHelper.finishingMatch=false GameHelper.playerChoosenartifactID=nil GameHelper.finishedChoosingArtifact=false GameHelper.finishedChoosingCardBucket=false GameHelper.finishedChoosingAdditionalCardBucket=false GameHelper.matchFinished=false GameHelper.playerChoosenDeck=true GameHelper.playerLeaderCard.isDeleted=false GameHelper.enemyLeaderCard.isDeleted=false GameHelper.finishedChoosingCards=false GameHelper.playerChoosenCards=false GameHelper.isPlayerTurn=true GameHelper.currentGameState=glGameStates.START_TURN GameHelper.playerNumOfTurnsWithoutCards=0 GameHelper.enemyNumOfTurnsWithoutCards=0 --todo: move this to ai helper class AIHelper.aiTurnTimeCur=0 AIHelper.aiDelayBeforeTurn=AIHelper.aiDelayBeforeTurnAmount AIHelper.aiTurnTimeOfNextAction=AIHelper.aiTimeBetweenActionsInSecs AIHelper.aiTimeForTurnInSecs=2.6 AIHelper.aiTimeForTurnInSecsBase=AIHelper.aiTimeForTurnInSecs AIHelper.aiTimeForTurnInSecsCur=AIHelper.aiTimeForTurnInSecs foreach(GUIHelper.playerBattlefieldCards,function(cardGUI) cardGUI.cardObj=nil end) foreach(GUIHelper.enemyBattlefieldCards,function(cardGUI) cardGUI.cardObj=nil end) foreach(GameHelper.playerBattlefieldCards,function(cardObj) cardObj.cardGUI=nil end) foreach(GameHelper.enemyBattlefieldCards,function(cardObj) cardObj.cardGUI=nil end) GameHelper.playerBattlefieldCards={} GameHelper.enemyBattlefieldCards={} for i=1,#GUIHelper.playerHandCards do local cardGUI=GUIHelper.playerHandCards[i] if cardGUI then cardGUI.border= glGUIFrameStyleUnusableCard.border end end local newTurnLeader=playerLeader GameHelper.currentTurnLeader=newTurnLeader newTurnLeader.stats.manaCount.max=math.min(RuleHelper.maxManaCount,newTurnLeader.stats.manaCount.max+1) newTurnLeader:RestoreMana() if GameHelper.tutorialPhase>0 and GameHelper.tutorialPhase<60 then Logger:Info("STARTING TUTORIAL PHASE:"..GameHelper.tutorialPhase,glMsgType.GAME_LOGIC) foreach(GUIHelper.playerBattlefieldCards,function(cardObj) cardObj.border= glGUIFrameStyleTotallyUnusableCard.border end) foreach(GUIHelper.enemyBattlefieldCards,function(cardObj) cardObj.border= glGUIFrameStyleTotallyUnusableCard.border end) GameHelper.ShowingInventoryScreen=false GameHelper.playerChoosenDeck=true local playerLeader=GameHelper.playerLeaderCard local playerLeaderStats=playerLeader.stats local enemyLeader=GameHelper.enemyLeaderCard local enemyLeaderStats=enemyLeader.stats GameHelper.playerHandCards={} GameHelper.playerDeckCards={} GameHelper.enemyHandCards={} GameHelper.enemyDeckCards={} glRerollStartingCardsGUI:hide() GameHelper.finishedChoosingCards=true if GameHelper.tutorialPhase<20 then glGameOptionsButton:visible(false) glEndTurnButton:visible(false) glEnemyToolbar:visible(false) glPlayerToolbar:visible(false) glPlayerLeaderCardGUI:visible(false) glEnemyLeaderCardGUI:visible(false) glEnemyToolbarMana:visible(false) glEnemyToolbarCards:visible(false) glPlayerToolbarMana:visible(false) glPlayerToolbarCards:visible(false) playerLeaderStats=GameHelper:InitLeaderCardStatsTable(1,0,1) enemyLeaderStats=GameHelper:InitLeaderCardStatsTable(1,0,0) enemyLeader.tags={} playerLeader.tags={} local tutFunc4=function(ref) glTutorialIsBlockingGUI=false end local tutFunc3=function(ref) glEndTurnButton:makeVisible() glTutorialIsBlockingGUI=true glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc4,{"^14To make unit ready to attack","^14end your current turn using","^14end turn button on the right."}) end local tutFunc2=function(ref) glEnemyLeaderCardGUI:makeVisible() glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc3,{"^14This is enemy leader unit.","^14If it dies you will win.","","^14To kill it, reduce its HP to 0.",}) end local tutFunc1=function(ref) glPlayerLeaderCardGUI:makeVisible() glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc2,{"Great work!","^14This is your leader unit.","^14If it dies you will lose."}) end glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc1,{"^15Please provide the proof you","possess the ability to read","by clicking 'OK' button."}) elseif GameHelper.tutorialPhase<30 then glGameOptionsButton:visible(false) glEndTurnButton:visible(false) glPlayerToolbar:visible(false) glEnemyToolbar:visible(false) glPlayerLeaderCardGUI:visible(false) glEnemyLeaderCardGUI:visible(false) glEnemyToolbarMana:visible(false) glEnemyToolbarCards:visible(false) glPlayerToolbarMana:visible(false) glPlayerToolbarCards:visible(false) playerLeaderStats=GameHelper:InitLeaderCardStatsTable(4,0,1) playerLeader.tags={} enemyLeaderStats=GameHelper:InitLeaderCardStatsTable(5,0,1) enemyLeader.tags={} GameHelper.playerDeckCards={deepcopy(GameHelper.allCards["U000"])} local tutFunc3=function(ref) end local tutFunc2=function(ref) playerLeader.stats.attacksAvail.cur=1 end local tutFunc1=function(ref) glEnemyLeaderCardGUI:makeVisible() glPlayerLeaderCardGUI:makeVisible() glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc2,{"Amazing!","Now, let's kill the enemy!"}) end glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc1,{"Congratulations!","^14You've won your first fight!","","^15Now, please provide the proof","you didn't forgot how to read","by clicking 'OK' button."}) elseif GameHelper.tutorialPhase<40 then glEnemyToolbarMana:visible(false) glEnemyToolbarCards:visible(false) glPlayerToolbarMana:visible(false) glPlayerToolbarCards:visible(false) glGameOptionsButton:visible(false) glEndTurnButton:visible(false) glPlayerToolbar:visible(false) glEnemyToolbar:visible(false) glEnemyToolbarMana:visible(false) glEnemyToolbarCards:visible(false) glPlayerLeaderCardGUI:visible(false) glEnemyLeaderCardGUI:visible(false) playerLeaderStats=GameHelper:InitLeaderCardStatsTable(4,0,1) playerLeader.tags={} enemyLeaderStats=GameHelper:InitLeaderCardStatsTable(5,0,1) enemyLeader.tags={} GameHelper.playerDeckCards={deepcopy(GameHelper.allCards["U000"]),deepcopy(GameHelper.allCards["U000"]),deepcopy(GameHelper.allCards["U000"]),deepcopy(GameHelper.allCards["A004"]),deepcopy(GameHelper.allCards["A004"]),deepcopy(GameHelper.allCards["A004"]),deepcopy(GameHelper.allCards["A004"])} GameHelper.enemyDeckCards={deepcopy(GameHelper.allCards["U000"]),deepcopy(GameHelper.allCards["U000"]),deepcopy(GameHelper.allCards["U000"]),deepcopy(GameHelper.allCards["U000"]),deepcopy(GameHelper.allCards["A004"]),deepcopy(GameHelper.allCards["A004"])} local tutFunc7=function(ref) GameHelper.tutorialPhase=32 AsyncQueueLogicHelper:AddToQueue(function(data) glTutorialDialog=GUIHelper:CreateTutorialDialog(function(ref) playerLeader.stats.manaCount.max=1 playerLeader.stats.manaCount.cur=1 playerLeader.stats.manaVisualCount.max=1 playerLeader.stats.manaVisualCount.cur=1 if glPlayerToolbar then ParticleHelper:CreateSummoningUnitFX(glPlayerToolbar.x+4,glPlayerToolbar:getCenterY()) end end,{"^14Each player starts 1st turn with 1 MANA","^14so you can play only 1-cost card now.","","^15Let's play one of them."})end,{},0) end local tutFunc6=function(ref) glPlayerToolbarMana:makeVisible() if glPlayerToolbar then ParticleHelper:CreateSummoningUnitFX(glPlayerToolbar:getCenterX()-50,glPlayerToolbar:getCenterY()) end GameHelper.tutorialPhase=31 AsyncQueueLogicHelper:AddToQueue(function(data) glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc7,{"^14And you need MANA points to spend them","^14by playing cards from hand."})end,{},1) end local tutFunc5=function(ref) GameHelper.enemyHandCards={} glEnemyToolbar:makeVisible() glEnemyToolbarCards:makeVisible() AsyncQueueLogicHelper:AddToQueue(function(data) GameHelper:ExecuteDrawCard(false)end,{},0.3) AsyncQueueLogicHelper:AddToQueue(function(data) GameHelper:ExecuteDrawCard(false)end,{},0.6) AsyncQueueLogicHelper:AddToQueue(function(data) GameHelper:ExecuteDrawCard(false)end,{},0.9) AsyncQueueLogicHelper:AddToQueue(function(data) GameHelper:ExecuteDrawCard(false)end,{},1.2) AsyncQueueLogicHelper:AddToQueue(function(data) glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc6,{"^14Cards require MANA to be played.","So let's give you MANA counter."})end,{},4) end local tutFunc4=function(ref) GameHelper.playerHandCards={} GameHelper:ExecuteDrawCard(true) AsyncQueueLogicHelper:AddToQueue(function(data) GameHelper:ExecuteDrawCard(true)end,{},0.4) AsyncQueueLogicHelper:AddToQueue(function(data) GameHelper:ExecuteDrawCard(true)end,{},0.8) AsyncQueueLogicHelper:AddToQueue(function(data) GameHelper:ExecuteDrawCard(true)end,{},1.2) glTutorialIsBlockingGUI=true AsyncQueueLogicHelper:AddToQueue(function(data) glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc5,{"^14Enemy has their own set of cards","^14And their own card counter","^14found next to their leader unit."})end,{},5) end local tutFunc3=function(ref) glPlayerToolbar:makeVisible() glPlayerToolbarCards:makeVisible() GameHelper.playerHandCards={} glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc4,{"^14Card counter shows how many cards","^14you have in hand/you have in the deck left.","","^15Now, let's draw your starting cards."}) end local tutFunc2=function(ref) glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc3,{"You have a deck, you know?","Let me show you!"}) end local tutFunc1=function(ref) glEnemyLeaderCardGUI:makeVisible() glPlayerLeaderCardGUI:makeVisible() glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc2,{"Wonderful!","","^14At the start of every fight","^14each side draw 4 cards","^14from their own deck."}) end glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc1,{"Congratulations!","^14You've won another fight!","","^15Third's time a charm?","Are you still capable of reading?","Confirm by clicking 'OK' button."}) elseif GameHelper.tutorialPhase<50 then GameHelper.finishedChoosingCards=false glGameOptionsButton:visible(false) glEndTurnButton:visible(false) glPlayerToolbar:visible(false) glEnemyToolbar:visible(false) glPlayerLeaderCardGUI:visible(false) glEnemyLeaderCardGUI:visible(false) playerLeaderStats=GameHelper:InitLeaderCardStatsTable(30,0,1) playerLeader.tags={} enemyLeaderStats=GameHelper:InitLeaderCardStatsTable(60,0,4) enemyLeader.tags={} GameHelper.playerDeckCards={deepcopy(GameHelper.allCards.TUTORIAL2),deepcopy(GameHelper.allCards.TUTORIAL2),deepcopy(GameHelper.allCards.TUTORIAL2),deepcopy(GameHelper.allCards.TUTORIAL2),deepcopy(GameHelper.allCards.TUTORIAL4),deepcopy(GameHelper.allCards.TUTORIAL4),deepcopy(GameHelper.allCards.TUTORIAL4),deepcopy(GameHelper.allCards.TUTORIAL4),deepcopy(GameHelper.allCards.TUTORIAL4),deepcopy(GameHelper.allCards.TUTORIAL4),deepcopy(GameHelper.allCards.TUTORIAL4),deepcopy(GameHelper.allCards.TUTORIAL4),deepcopy(GameHelper.allCards.TUTORIAL4),deepcopy(GameHelper.allCards.TUTORIAL4),deepcopy(GameHelper.allCards.TUTORIAL4),} GameHelper.enemyDeckCards={deepcopy(GameHelper.allCards.TUTORIAL1),deepcopy(GameHelper.allCards.TUTORIAL1),deepcopy(GameHelper.allCards.TUTORIAL1),deepcopy(GameHelper.allCards.TUTORIAL1),deepcopy(GameHelper.allCards.TUTORIAL1),deepcopy(GameHelper.allCards.TUTORIAL1),deepcopy(GameHelper.allCards.TUTORIAL1),} local tutFunc2=function(ref) glTutorialIsBlockingGUI=false glEnemyToolbar:makeVisible() glPlayerToolbar:makeVisible() glEnemyToolbar:show() glPlayerToolbar:show() playerLeader.stats.manaCount.max=1 playerLeader.stats.manaCount.cur=1 playerLeader.stats.manaVisualCount.max=1 playerLeader.stats.manaVisualCount.cur=1 GameHelper:ExecuteDrawCard(true) GameHelper:ExecuteDrawCard(true) GameHelper:ExecuteDrawCard(true) GameHelper:ExecuteDrawCard(true) AsyncQueueLogicHelper:AddToQueue(function(data) if not glChooseStaringCardsGUI then GUICreator:CreateRedrawingStartingCardsScreen() end glChooseStaringCardsGUI:show() end,{},1) end local tutFunc1=function(ref) glEnemyToolbar:show() glPlayerToolbar:show() glEnemyToolbar:makeVisible() glPlayerToolbar:makeVisible() glPlayerLeaderCardGUI:makeVisible() glEnemyLeaderCardGUI:makeVisible() glEndTurnButton:makeVisible() glTutorialIsBlockingGUI=true glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc2,{"Wonderful!","","^14At the start of every fight","^14you can redraw any or all","^14cards from hand."}) GameHelper.tutorialPhase=41 end glEnemyToolbar:hide() glPlayerToolbar:hide() glTutorialDialog=GUIHelper:CreateTutorialDialog(function(ref) glTutorialDialog=GUIHelper:CreateTutorialDialog(function(ref) glTutorialDialog=GUIHelper:CreateTutorialDialog(function(ref) glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc1,{"Please confirm it by clicking 'OK' button."}) end,{"..."}) end,{"^15Now,","there is no reason to still suspect","that you aren't capable of reading...",}) end,{"Wow!","^You've won yet another fight!"}) end playerLeader.stats=playerLeaderStats enemyLeader.stats=enemyLeaderStats EventHelper:ExecuteEvent(glEventTypes.TUTORIAL_INIT,self,simulateOnly,{phase=GameHelper.tutorialPhase}) else AsyncQueueLogicHelper:AddToQueue(function(data) SfxHelper:PlaySFX(glSFXUnitSummoned,nil,30) end,{},0.1) local playerCard=GUIHelper.playerLeaderCard local enemyCard=GUIHelper.enemyLeaderCard if playerCard then ParticleHelper:CreateSummoningUnitFX(playerCard:getCenterX(),playerCard.y+playerCard.h) end if enemyCard then ParticleHelper:CreateSummoningUnitFX(enemyCard:getCenterX(),enemyCard.y+enemyCard.h) end enemyCard.border= glGUIFrameStyleUnusableCard.border playerCard.border= glGUIFrameStyleUnusableCard.border foreach(GUIHelper.playerBattlefieldCards,function(cardObj) cardObj.border= glGUIFrameStyleTotallyUnusableCard.border end) foreach(GUIHelper.enemyBattlefieldCards,function(cardObj) cardObj.border= glGUIFrameStyleTotallyUnusableCard.border end) GUIHelper.playerLeaderCard=playerCard GUIHelper.enemyLeaderCard=enemyCard glGameOptionsButton:visible(true) end local playerLeader=GameHelper.playerLeaderCard foreach(playerLeader.tags,function(tag) if tag.funcAfterInit then tag:funcAfterInit(playerLeader) end if tag.funcAfterBeingSummoned then tag:funcAfterBeingSummoned(playerLeader) end end) local enemyLeader=GameHelper.enemyLeaderCard Logger:Trace("ENEMY LEADER TAGS:"..(#enemyLeader.tags),glMsgType.GAME_LOGIC) foreach(enemyLeader.tags,function(tag) if tag.funcAfterInit then tag:funcAfterInit(enemyLeader) end if tag.funcAfterBeingSummoned then tag:funcAfterBeingSummoned(enemyLeader) end end) if debug then enemyLeader.stats=GameHelper:InitLeaderCardStatsTable(1,0,0) end Logger:Info("STARTED NEW MATCH",glMsgType.GAME_LOGIC) EventHelper:ExecuteEvent(glEventTypes.MATCH_STARTED,self,simulateOnly,{}) end function GameHelper:ProcessPlayerTurnLogic(deltaTime,selCardGUI1st,cardObj1st,statsCard1st,selCardGUI2nd,cardObj2nd,statsCard2nd) --TODO: make this work for ai as well if GameHelper.currentGameState==glGameStates.CASTING_SPELL then -- if cardObj1st and statsCard1st.manaCost.cur<=GameHelper.playerLeaderCard.stats.manaCount.cur then if cardObj2nd then local tutorialNotAllow=(GameHelper.tutorialPhase>45 and (cardObj2nd.isLeaderCard or not cardObj2nd.isPlayerCard)) local tagArmorTutorial=cardObj1st:GetTagByName("ARMORBUFF_TUTORIAL") if tagArmorTutorial then tutorialNotAllow = tutorialNotAllow and #tagArmorTutorial.canTarget>0 end if not tutorialNotAllow then GameHelper.playerLeaderCard:SpendMana(statsCard1st.manaCost.cur) GameHelper:CastSpellAction(cardObj1st,selCardGUI1st,cardObj2nd,selCardGUI2nd,false) table.remove(GameHelper.playerHandCards,selCardGUI1st.pos) end else --TODO: add support for spells that doesn't require target end end end if GameHelper.currentGameState==glGameStates.UNIT_SUMMON then if cardObj1st and statsCard1st.manaCost.cur<=GameHelper.playerLeaderCard.stats.manaCount.cur then GameHelper.playerLeaderCard:SpendMana(statsCard1st.manaCost.cur) GameHelper:SummonUnitOntoBattlefield(cardObj1st,selCardGUI2nd.pos,true) table.remove(GameHelper.playerHandCards,selCardGUI1st.pos) end end if GameHelper.currentGameState==glGameStates.UNIT_ATTACK_LEADER or GameHelper.currentGameState==glGameStates.UNIT_ATTACK_UNIT then Logger:Debug("attacking enemy",glMsgType.GAME_LOGIC) if cardObj1st and cardObj2nd then if cardObj1st:CanExecuteAttack() then GameHelper:ExecuteAttackAction(cardObj1st,selCardGUI1st,cardObj2nd,selCardGUI2nd) end end end if GameHelper.currentGameState>1 then GameHelper.cardGUIElemSelected1st=nil GameHelper.cardGUIElemSelected=nil GameHelper.currentGameState=glGameStates.TURN_IN_PROGRESS end foreach(glGameStates,function(v,k) if GameHelper.currentGameState==v then end end) end function GameHelper:ParseAndProcessPlayerTurnForGUI(deltaTime,selCardGUI1st,cardObj1st,statsCard1st,selCardGUI2nd,cardObj2nd,statsCard2nd) GameHelper.haveStuffToDo=selCardGUI1st --GUICARDS LOGIC if selCardGUI2nd then AIHelper:SetMoveDesc("") --both cards selected, determine what is happenning Logger:Trace("selected card 2nd:"..selCardGUI2nd.name,glMsgType.GUI) if selCardGUI1st then Logger:Trace("selected card 1st:"..selCardGUI1st.name,glMsgType.GUI) if(selCardGUI1st~=selCardGUI2nd) then Logger:Trace("diff. cards",glMsgType.GUI) if selCardGUI1st.isPlayerCard then Logger:Trace("1st player card",glMsgType.GUI) if cardObj1st.isSpell then local additionalCheck=(not selCardGUI2nd.isHandCard) if additionalCheck then GameHelper.currentGameState=glGameStates.CASTING_SPELL Logger:Trace("casting spell",glMsgType.GUI) end else if selCardGUI2nd.isPlayerCard then Logger:Trace("2nd player card",glMsgType.GUI) --put unit unto battlefield if not selCardGUI2nd.isHandCard and selCardGUI2nd.pos and not GameHelper.playerBattlefieldCards[selCardGUI2nd.pos] and selCardGUI1st.isHandCard then GameHelper.currentGameState=glGameStates.UNIT_SUMMON end else Logger:Trace("2nd enemy card",glMsgType.GUI) --player attacks enemy if not selCardGUI1st.isHandCard then local additionalCheck=cardObj2nd and cardObj2nd:CanBeAttacked(GameHelper.enemyBattlefieldCards,cardObj1st) if additionalCheck then if selCardGUI2nd.isLeaderCard then GameHelper.currentGameState=glGameStates.UNIT_ATTACK_LEADER else GameHelper.currentGameState=glGameStates.UNIT_ATTACK_UNIT end end end end end glMouse.forceX=-100 glMouse.forceY=-100 else Logger:Trace("1st enemy card",glMsgType.GUI) if selCardGUI2nd.isPlayerCard then Logger:Trace("2nd player card",glMsgType.GUI) else Logger:Trace("2nd enemy card",glMsgType.GUI) end end end GameHelper.cardGUIElemSelected1st=nil else if selCardGUI2nd.isPlayerCard and statsCard2nd and ((selCardGUI2nd.isHandCard and (GameHelper.playerLeaderCard.stats.manaCount.cur>=statsCard2nd.manaCost.cur)) or (((not selCardGUI2nd.isHandCard) and statsCard2nd.attacksAvail and (statsCard2nd.attacksAvail.cur>0)))) then Logger:Trace("set GameHelper.cardGUIElemSelected1st:"..statsCard2nd.manaCost.cur..";"..GameHelper.playerLeaderCard.stats.manaCount.cur,glMsgType.GUI) GameHelper.cardGUIElemSelected1st=selCardGUI2nd end end GameHelper.cardGUIElemSelected=nil elseif selCardGUI1st then --first card is selected but player didn't click second time --logic for color for line from card to mouse local cardGUIHover=GUIHelper.controlHoveredOver local touchControls=GameHelper.controlScheme==2 if cardGUIHover or touchControls then if touchControls and not cardGUIHover then cardGUIHover={} --hack to make less refactoring for touch controls end StateHelper.cardObjHovered=cardGUIHover.cardObj if selCardGUI1st.isHandCard then if cardObj1st.isSpell then AIHelper:SetMoveDesc("Select target unit") GUIHelper.lineHelperColor=(cardGUIHover.cardObj and (not cardGUIHover.isHandCard)) and 11 or 6 if cardGUIHover.cardObj and GameHelper.tutorialPhase>45 and GUIHelper.lineHelperColor then GUIHelper.lineHelperColor=(cardGUIHover.cardObj.isPlayerCard and not cardGUIHover.cardObj.isLeaderCard) and 11 or 6 end foreach(GUIHelper.enemyBattlefieldCards,function(cardGUI) cardGUI.border= cardGUI.cardObj and glGUIFrameStyleActiveOKCard.border or glGUIFrameStyleTotallyUnusableCard.border end) if GameHelper.tutorialPhase<40 then GUIHelper.enemyLeaderCard.border=glGUIFrameStyleActiveOKCard.border GUIHelper.playerLeaderCard.border=glGUIFrameStyleActiveOKCard.border else GUIHelper.enemyLeaderCard.border=glGUIFrameStyleTotallyUnusableCard.border GUIHelper.playerLeaderCard.border=glGUIFrameStyleTotallyUnusableCard.border end foreach(GUIHelper.playerBattlefieldCards,function(cardGUI) cardGUI.border= cardGUI.cardObj and glGUIFrameStyleActiveOKCard.border or glGUIFrameStyleTotallyUnusableCard.border end) if StateHelper.cardObjHovered and selCardGUI1st~=cardGUIHover and not cardGUIHover.isHandCard then --todo: FIX THIS hack if cardObj1st.id~="S007" then local regen=(not GameHelper.simulatedCardObj1) or (not GameHelper.simulatedCardObj2) if not regen then --check if cards are different --TODO: add unique ID to fix bug when to not refresh for other cards that happen to have same id!! regen=GameHelper.simulatedCardObj1.id~=StateHelper.cardObjHovered.id or GameHelper.simulatedCardObj2.id~=cardObj1st.id end local hoverCardObjCopy=regen and StateHelper.cardObjHovered:DeepCopy() or GameHelper.simulatedCardObj1 local selCardObjCopy=regen and cardObj1st:DeepCopy() or GameHelper.simulatedCardObj2 if regen then GameHelper:SimulateCastingSpellAction(selCardObjCopy,hoverCardObjCopy) GameHelper.simulatedCardObj1=hoverCardObjCopy GameHelper.simulatedCardObj2=selCardObjCopy end cardGUIHover.simulatedCardObj=hoverCardObjCopy end end else AIHelper:SetMoveDesc("Select where to summon your unit") --player is summoning unit GUIHelper.lineHelperColor=(not cardGUIHover.cardObj and cardGUIHover.isPlayerCard) and 11 or 6 foreach(GUIHelper.enemyBattlefieldCards,function(cardGUI) cardGUI.border=glGUIFrameStyleTotallyUnusableCard.border end) GUIHelper.enemyLeaderCard.border=glGUIFrameStyleTotallyUnusableCard.border GUIHelper.playerLeaderCard.border=glGUIFrameStyleTotallyUnusableCard.border foreach(GUIHelper.playerBattlefieldCards,function(cardGUI) cardGUI.border=(cardGUI.cardObj and glGUIFrameStyleTotallyUnusableCard or glGUIFrameStyleActiveOKCard).border end) end else AIHelper:SetMoveDesc("Select enemy unit to attack") local additionalCheck=true local additionalInfo={} --TODO: move this to GameHelper:CardCanBeAttacked foreach(GUIHelper.enemyBattlefieldCards,function(cardGUI) if cardGUI.cardObj then additionalCheck=cardGUI.cardObj:CanBeAttacked(GameHelper.enemyBattlefieldCards,cardObj1st,true) cardGUI.border=(additionalCheck and glGUIFrameStyleActiveOKCard or glGUIFrameStyleTotallyUnusableCard).border end end) additionalCheck=GameHelper.enemyLeaderCard:CanBeAttacked(GameHelper.enemyBattlefieldCards,cardObj1st,true) local hoverCardObj=cardGUIHover.cardObj GUIHelper.enemyLeaderCard.border=(additionalCheck and glGUIFrameStyleActiveOKCard or glGUIFrameStyleTotallyUnusableCard).border GUIHelper.playerLeaderCard.border=glGUIFrameStyleTotallyUnusableCard.border foreach(GUIHelper.playerBattlefieldCards,function(cardGUI) cardGUI.border=glGUIFrameStyleTotallyUnusableCard.border end) --player is attacking if hoverCardObj then additionalCheck,additionalInfo=hoverCardObj:CanBeAttacked(GameHelper.enemyBattlefieldCards,cardObj1st,true) else additionalCheck=true end GUIHelper.lineHelperColor=(StateHelper.cardObjHovered and not cardGUIHover.isPlayerCard and additionalCheck) and 11 or 6 local canAttack=true if not additionalCheck and hoverCardObj and (not hoverCardObj.isPlayerCard) then canAttack=false GameHelper.simulatedCardObj1=nil GameHelper.simulatedCardObj2=nil local distractsInfo=additionalInfo[1] local tagsInfo=additionalInfo[2] AIHelper:SetMoveDesc("You can't attack that unit!") --show why player cant attack as tooltip if GameHelper.cardGUIHoveredTime>GameHelper.delayBeforeShowingWhyCantAttack then table.insert(glGUIFrameMouseTooltip.textArray,{text="YOU CAN'T ATTACK THIS UNIT",color=14,smallFont=false}) if distractsInfo and distractsInfo.list and (#distractsInfo.list)>0 then local list=distractsInfo.list table.insert(glGUIFrameMouseTooltip.textArray,{text="- There "..((#list>1) and ("are "..(#list).." other units") or "is other unit").." with DISTRACT tag",color=15,smallFont=true}) end if tagsInfo and tagsInfo.list and (#tagsInfo.list)>0 then local list=tagsInfo.list local str="- because of TAGs: " local i=0 foreach(list,function(tag) str=str..tag.name..((i+1)<(#list) and ", " or "") i=i+1 end) table.insert(glGUIFrameMouseTooltip.textArray,{text=str,color=15,smallFont=true}) end end end --todo: use GameHelper.controlScheme==2 on first cardguihover check but make sure game doesnt call it! if cardGUIHover or touchControls then if cardObj1st and StateHelper.cardObjHovered and selCardGUI1st~=cardGUIHover and not cardGUIHover.isHandCard and not cardGUIHover.isPlayerCard then local regen=(not GameHelper.simulatedCardObj1) or (not GameHelper.simulatedCardObj2) if not regen then --check if cards are different --TODO: add unique ID to fix bug regen=GameHelper.simulatedCardObj1.id~=StateHelper.cardObjHovered.id or GameHelper.simulatedCardObj2.id~=cardObj1st.id end local hoverCardObjCopy=regen and StateHelper.cardObjHovered:DeepCopy() or GameHelper.simulatedCardObj1 local selCardObjCopy=regen and cardObj1st:DeepCopy() or GameHelper.simulatedCardObj2 if regen then GameHelper:SimulateAttackAction(selCardObjCopy,hoverCardObjCopy) additionalCheck=StateHelper.cardObjHovered:CanBeAttacked(GameHelper.enemyBattlefieldCards,cardObj1st) GameHelper.simulatedCardObj1=hoverCardObjCopy GameHelper.simulatedCardObj2=selCardObjCopy end if additionalCheck then cardGUIHover.simulatedCardObj=hoverCardObjCopy selCardGUI1st.simulatedCardObj=selCardObjCopy end else GameHelper.simulatedCardObj1=nil GameHelper.simulatedCardObj2=nil end else GameHelper.simulatedCardObj1=nil GameHelper.simulatedCardObj2=nil end end foreach(GUIHelper.playerHandCards,function(cardGUI) cardGUI.border= glGUIFrameStyleTotallyUnusableCard.border end) else GameHelper.simulatedCardObj1=nil GameHelper.simulatedCardObj2=nil --mouse is on nothing in particular GUIHelper.lineHelperColor=10 end else AIHelper:SetMoveDesc("") --indicate via visuals what player can do this turn if not GameHelper.isPlayerTurn then foreach(GUIHelper.enemyBattlefieldCards,function(cardGUI) cardGUI.border=glGUIFrameStyleTotallyUnusableCard.border end) GUIHelper.playerLeaderCard.border=glGUIFrameStyleUnusableCard.border GUIHelper.enemyLeaderCard.border=glGUIFrameStyleUnusableCard.border foreach(GUIHelper.playerBattlefieldCards,function(cardGUI) cardGUI.border=glGUIFrameStyleTotallyUnusableCard.border end) foreach(GUIHelper.playerHandCards,function(cardGUI) cardGUI.border=glGUIFrameStyleUnusableCard.border end) else foreach(GUIHelper.enemyBattlefieldCards,function(cardGUI) cardGUI.border=(cardGUI.cardObj and glGUIFrameStyleUnusableCard or glGUIFrameStyleTotallyUnusableCard).border end) glEnemyLeaderCardGUI.border=glGUIFrameStyleUnusableCard.border glPlayerLeaderCardGUI.border=((glPlayerLeaderCardGUI.cardObj and glPlayerLeaderCardGUI.cardObj.stats.attacksAvail.cur>0 and glPlayerLeaderCardGUI.cardObj.stats.attack.cur>0) and glGUIFrameStyleActiveOKCard or glGUIFrameStyleUnusableCard).border foreach(GUIHelper.playerBattlefieldCards,function(cardGUI) cardGUI.border=(cardGUI.cardObj and ((cardGUI.cardObj.stats.attacksAvail.cur>0 and cardGUI.cardObj.stats.attack.cur>0) and glGUIFrameStyleActiveOKCard or glGUIFrameStyleUnusableCard) or glGUIFrameStyleTotallyUnusableCard).border end) foreach(GUIHelper.playerHandCards,function(cardGUI) --TODO: LOOK HERE cardGUI.border=(cardGUI.cardObj and (GameHelper.playerLeaderCard.stats.manaCount.cur>=cardGUI.cardObj.stats.manaCost.cur) and glGUIFrameStyleActiveOKCard or glGUIFrameStyleUnusableCard).border end) end end end function GameHelper:ProcessAITurn(deltaTime) if GameHelper.tutorialPhase>0 and GameHelper.tutorialPhase<20 then AIHelper.aiTurnTimeCur=AIHelper.aiTurnTimeCur+deltaTime Logger:Debug("AI TUTORIAL TURN",glMsgType.TUTORIAL) if AIHelper.aiTurnTimeCur>=2 then GameHelper:EndTurn() AIHelper.aiTurnTimeCur=0 end else --TODO: add delays AIHelper:ExecuteTurn(deltaTime) end end function GameHelper:FindTagInCard(cardObj,tagName) --TODO: move this to cardclass local t=nil if cardObj and cardObj.tags then for id=1,(cardObj.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=cardObj.tags[id] if (tag and tag.name==tagName) or (tag and tag.id==tagName) then t=tag return t end end end return t end function GameHelper:EndMatch(playerWon,inDungeonRun) AIHelper.turnFinished=false GameHelper.turnCounter=1 GameHelper.finishingMatch=true glEndTurnButton:visible(false) glGameOptionsButton:visible(false) if inDungeonRun then --increase every finished match to upgrade leader to be more resilent in later runs GameHelper.playerLeaderFormula.stats.hp.max=GameHelper.playerLeaderFormula.stats.hp.max+1 GameHelper.playerLeaderFormula.stats.armor.max=GameHelper.playerLeaderFormula.stats.armor.max+1 GameHelper.playerLeaderCard=GameHelper.playerLeaderFormula:DeepCopy() playerLeaderStats=GameHelper.playerLeaderCard.stats playerLeaderStats.hp:setToMax() playerLeaderStats.armor:setToMax() playerLeaderStats.attack:setToMax() end if playerWon then Logger:Info("PLAYER WON MATCH",glMsgType.GAME_LOGIC) GameHelper.playerWon=true if GameHelper.gamesWon>=((#glDungeonRunDeckList)-1) then if not GameHelper.ShowedEndGameSummary then GameHelper.ShowedEndGameSummary=true AsyncQueueLogicHelper:AddToQueue(function(data) GUIHelper.ShowEndGameSummaryScreen() end,{},1.5) end else AsyncQueueLogicHelper:AddToQueue(function(data) GameHelper.matchFinished=true GameHelper.gamesWon=GameHelper.gamesWon+1 GameHelper.playerChoosenCards=false GameHelper.playerChoosenDeck=false GameHelper.ShowedInventoryScreen=false GameHelper.showedRunProgressBeforeEvent=false GameHelper.enemyLeaderCardToOfferForPlayer=GameHelper.enemyLeaderCard.unitIDBasedOn if GameHelper.enemyLeaderCardToOfferForPlayer then Logger:Debug("OFFERING CARD:"..GameHelper.enemyLeaderCardToOfferForPlayer,glMsgType.GAME_LOGIC) end end,{},3) end else Logger:Info("PLAYER LOSE MATCH",glMsgType.GAME_LOGIC) self.playerWon=false self.currentPlayerLives=GameHelper.currentPlayerLives-1 self.lostPlayerLives=GameHelper.lostPlayerLives+1 if self.currentPlayerLives<=0 then if not self.ShowedEndGameSummary then GUIHelper.ShowEndGameSummaryScreen() end else AsyncQueueLogicHelper:AddToQueue(function(data) GameHelper.matchFinished=true GameHelper.artifactsEncounterLvl=GameHelper.artifactsEncounterLvl+1 GameHelper.playerChoosenCards=false GameHelper.playerChoosenDeck=false GameHelper.ShowedInventoryScreen=false GameHelper.showedRunProgressBeforeEvent=false end,{},3) end end AIHelper:SetMoveDesc("") end function GameHelper:ForceEndMatch(playerWon) local cardObj=self[(playerWon and "enemyLeaderCard" or "playerLeaderCard")] local selCardGUI=cardObj.cardGUI local value=cardObj.stats.hp.cur+cardObj.stats.armor.cur+1 local attackingCardGUI=selCardGUI self:ApplyDamageTo(cardObj,selCardGUI,attackingCardGUI,value,0,false) end function GameHelper:GenerateVariationOfTheDeck(id,numOfCards) local temp=glCSVDecksDefinitionsByID[id] local deck={} foreach(temp.keyCards,function(cardID) table.insert(deck,cardID) end) foreach(temp.supportingCards,function(cardInfo) if(#deck0 then ldForm=table.remove(leadersList,math.random(#leadersList)) deck=ldForm.deckID ld=GameHelper.allCards[ldForm.id]:DeepCopy() ld:DeepCopy() if subTier>1 then for i=1,subTier-1 do ld.stats.hp.max=ld.stats.hp.max+ldForm.upgradePerSubLvl.hp ld.stats.armor.max=ld.stats.armor.max+ldForm.upgradePerSubLvl.armor ld.stats.attack.max=ld.stats.attack.max+ldForm.upgradePerSubLvl.atk end end end Logger:Debug("Generated enemy Leader:"..ld.id.." for:"..tier..";"..subTier..";with stats:"..ld.stats.attack.max..";"..ld.stats.hp.max..";"..ld.stats.armor.max..";tags:"..(#ld.tags),glMsgType.GAME_LOGIC) return ld,deck end function GameHelper:GenerateDungeonRun(nLvl1,nLvl2,nLvl3) local debug=false local decks={} local leaders={} local lList1=glEnemyLeadersByLevel[1] local lList2=glEnemyLeadersByLevel[2] local lList3=glEnemyLeadersByLevel[3] local lList4=glEnemyLeadersByLevel[4] if glDebugMode then lList1={ {deckID="DECK001",id="L033",upgradePerSubLvl={hp=0,armor=0,atk=0}}, {deckID="DECK001",id="L033",upgradePerSubLvl={hp=0,armor=0,atk=0}} } end for i=1,nLvl1 do local ldID=math.random(8) local ld,deck=self:GenerateDungeonEnemy(ldID,1,i,lList1) table.insert(leaders,ld) table.insert(decks,deck) end for i=1,nLvl2 do local ldID=math.random(8) local ld,deck=self:GenerateDungeonEnemy(ldID,2,i,lList2) table.insert(leaders,ld) table.insert(decks,deck) end for i=1,nLvl3 do local ldID=math.random(8) local ld,deck=self:GenerateDungeonEnemy(ldID,3,i,lList3) table.insert(leaders,ld) table.insert(decks,deck) end --TODO: do more with boss unit local ldID=math.random(8) local ld,deck=self:GenerateDungeonEnemy(ldID,4,1,lList4) table.insert(leaders,ld) table.insert(decks,deck) glDungeonRunDeckList=decks glDungeonRunEnemyLeaderList=leaders Logger:Debug("generated run with:"..#decks.." decks and:"..#leaders.." leaders",glMsgType.GAME_LOGIC) end function GameHelper:GenerateNewBucketOptions() if not glChooseBucketsGUI then GUICreator:CreateChooseBucketsScreen() end local usableBuckets={} foreach(glCardBuckets,function(bucket) if bucket.buckets and #bucket.buckets>0 then if not bucket.unique or not table.contains(GameHelper.playerLeaderCard.bucketsList,bucket) then table.insert(usableBuckets,bucket) end end end) Logger:Trace("a:"..#usableBuckets,glMsgType.GAME_LOGIC) local progressBucketName=(GameHelper.gamesWon<2 and "SMALL" or (GameHelper.gamesWon<4 and "MEDIUM" or "LARGE")) Logger:Trace("progress bucket:"..progressBucketName,glMsgType.GAME_LOGIC) GameHelper.bucketOption1=glCardBuckets[progressBucketName] GameHelper.bucketOption2=table.remove(usableBuckets,math.random(#usableBuckets)) GameHelper.bucketOption3=table.remove(usableBuckets,math.random(#usableBuckets)) GameHelper.bucketOption1Var=math.random(#GameHelper.bucketOption1.buckets) GameHelper.bucketOption2Var=math.random(#GameHelper.bucketOption2.buckets) GameHelper.bucketOption3Var=math.random(#GameHelper.bucketOption3.buckets) if not GameHelper.bucketOption1.buckets[GameHelper.bucketOption1Var] then GameHelper.bucketOption1Var=math.random(#GameHelper.bucketOption1.buckets) end local i1=GameHelper.bucketOption1.buckets[GameHelper.bucketOption1Var][1] local i2=GameHelper.bucketOption1.buckets[GameHelper.bucketOption1Var][2] local i3=GameHelper.bucketOption1.buckets[GameHelper.bucketOption1Var][3] if i1 then glChooseBucketsGUI.optionsGUI[1].cardsGUI[1].cardObj=GameHelper.allCards[i1] end if i2 then glChooseBucketsGUI.optionsGUI[1].cardsGUI[2].cardObj=GameHelper.allCards[i2] end if i3 then glChooseBucketsGUI.optionsGUI[1].cardsGUI[3].cardObj=GameHelper.allCards[i3] end if not GameHelper.bucketOption2.buckets[GameHelper.bucketOption2Var] then GameHelper.bucketOption2Var=math.random(#GameHelper.bucketOption2.buckets) end local j1=GameHelper.bucketOption2.buckets[GameHelper.bucketOption2Var][1] local j2=GameHelper.bucketOption2.buckets[GameHelper.bucketOption2Var][2] local j3=GameHelper.bucketOption2.buckets[GameHelper.bucketOption2Var][3] if j1 then glChooseBucketsGUI.optionsGUI[2].cardsGUI[1].cardObj=GameHelper.allCards[j1] end if j2 then glChooseBucketsGUI.optionsGUI[2].cardsGUI[2].cardObj=GameHelper.allCards[j2] end if j3 then glChooseBucketsGUI.optionsGUI[2].cardsGUI[3].cardObj=GameHelper.allCards[j3] end if not GameHelper.bucketOption3.buckets[GameHelper.bucketOption3Var] then GameHelper.bucketOption3Var=math.random(#GameHelper.bucketOption3.buckets) end local k1=GameHelper.bucketOption3.buckets[GameHelper.bucketOption3Var][1] local k2=GameHelper.bucketOption3.buckets[GameHelper.bucketOption3Var][2] local k3=GameHelper.bucketOption3.buckets[GameHelper.bucketOption3Var][3] if k1 then glChooseBucketsGUI.optionsGUI[3].cardsGUI[1].cardObj=GameHelper.allCards[k1] end if k2 then glChooseBucketsGUI.optionsGUI[3].cardsGUI[2].cardObj=GameHelper.allCards[k2] end if k3 then glChooseBucketsGUI.optionsGUI[3].cardsGUI[3].cardObj=GameHelper.allCards[k3] end Logger:Trace("choosen buckets ids:"..GameHelper.bucketOption1Var..";"..GameHelper.bucketOption2Var..";"..GameHelper.bucketOption3Var,glMsgType.GAME_LOGIC) end function GameHelper:GenerateNewArtifactOptions(lvl) --TODO: move those to init betweenmatchesstate? local duplartifacts={} foreach(glLeaderArtifacts,function(artifact) if artifact.enabled then if not artifact.unique or not table.contains(GameHelper.playerLeaderCard.artifactsIDList,artifact.id) then if (not artifact.lvl) or artifact.lvl<=lvl then table.insert(duplartifacts,artifact) end end end end) GameHelper.artifactOption1=table.remove(duplartifacts,math.random(#duplartifacts)) GameHelper.artifactOption2=table.remove(duplartifacts,math.random(#duplartifacts)) GameHelper.artifactOption3=table.remove(duplartifacts,math.random(#duplartifacts)) local i=1 foreach(glChooseartifactGUI.optionsGUI,function(optionGUI) optionGUI.descGUI.resultTexts={} foreach((i==1 and GameHelper.artifactOption1 or (i==2 and GameHelper.artifactOption2 or GameHelper.artifactOption3)).desc,function(d) GUIHelper:InsertUnparsedTextIntoTextGUIFrame(d.str,optionGUI.descGUI) end) i=i+1 optionGUI.descGUI.scroll=0.9 end) end function GameHelper:SetAIBasedOnGameProgress(gamesWon,justLostMatch) end function GameHelper:SaveAvatarToPMEM() local option1=self.playerLeaderCard.sprite Logger:Debug("SAVING AVATAR OPTIONS",glMsgType.INIT_BASE) local pmemVal=option1 pmem(251,pmemVal) Logger:Info("Saved CTRL variable:"..pmemVal..";in pmem:251",glMsgType.INIT_BASE) end function GameHelper:LoadAvatarFromPMEM() local option1=1 Logger:Debug("LOADING CTRL OPTIONS",glMsgType.INIT_BASE) local pmemVal=pmem(251) Logger:Info("Loaded AVATAR variable:"..pmemVal..";in pmem:251",glMsgType.INIT_BASE) if pmemVal==0 then return end option1=pmemVal Logger:Debug(" option1:"..option1,glMsgType.INIT_BASE) self.playerLeaderCard.sprite=option1 end function GameHelper:SaveBaseOptionsToPMEM() local option1=AIHelper.AIDifficulty Logger:Debug("SAVING BASE OPTIONS",glMsgType.INIT_BASE) Logger:Debug(" option1:"..option1,glMsgType.INIT_BASE) local option2=GameHelper.gameModeDifficulty Logger:Debug(" option2:"..option2,glMsgType.INIT_BASE) local option3=GameHelper.delayBeforeShowingFullCard Logger:Debug(" option3:"..option3,glMsgType.INIT_BASE) local option4=GameHelper.delayBeforeShowingTooltips Logger:Debug(" option4:"..option4,glMsgType.INIT_BASE) local option5=GameHelper.animationSpeed Logger:Debug(" option5:"..option5,glMsgType.INIT_BASE) local option6=AIHelper.AISpeedMult Logger:Debug(" option6:"..option6,glMsgType.INIT_BASE) local option7=0 Logger:Debug(" option7:"..option7,glMsgType.INIT_BASE) local option8=GameHelper.controlScheme Logger:Debug(" option8:"..option8,glMsgType.INIT_BASE) --max 4294967295, so safe option is 3999999999 --some options have *100 instead *10 because of half values --3999999999 --8765443321 - how options map into variable local pmemVal=option1+option2*10+option3*1000+option4*100000+option5*1000000+option6*10000000+option7*100000000+option8*1000000000 pmem(252,pmemVal) Logger:Info("Saved base options variable:"..pmemVal..";in pmem:252",glMsgType.INIT_BASE) end function GameHelper:LoadMoreOptionsFromPMEM() local option1=0 local option2=0 local option3=0 local option4=0 local option5=0 local option6=0 local option7=0 local option8=0 Logger:Debug("LOADING MORE OPTIONS",glMsgType.INIT_BASE) local pmemVal=pmem(250) Logger:Info("Loaded options variable:"..pmemVal..";in pmem:250",glMsgType.INIT_BASE) if pmemVal==0 then return end option1=pmemVal%10 pmemVal=pmemVal-option1 Logger:Debug(" option1:"..option1,glMsgType.INIT_BASE) option2=pmemVal%100 pmemVal=pmemVal-option2 option2=option2/10 Logger:Debug(" option2:"..option2,glMsgType.INIT_BASE) GameHelper.playedTutorial=option1 GameHelper.showFullCardPreviewInBattle=option2 end function GameHelper:SaveMoreOptionsToPMEM() local option1=GameHelper.playedTutorial and 1 or 0 Logger:Debug("SAVING MORE OPTIONS",glMsgType.INIT_BASE) Logger:Debug(" option1:"..option1,glMsgType.INIT_BASE) local option2=GameHelper.showFullCardPreviewInBattle or 0 Logger:Debug(" option2:"..option2,glMsgType.INIT_BASE) local option3=0 Logger:Debug(" option3:"..option3,glMsgType.INIT_BASE) local option4=0 Logger:Debug(" option4:"..option4,glMsgType.INIT_BASE) local option5=0 Logger:Debug(" option5:"..option5,glMsgType.INIT_BASE) local option6=0 Logger:Debug(" option6:"..option6,glMsgType.INIT_BASE) local option7=0 Logger:Debug(" option7:"..option7,glMsgType.INIT_BASE) local option8=0 Logger:Debug(" option8:"..option8,glMsgType.INIT_BASE) local pmemVal=option1+option2*10+option3*1000+option4*100000+option5*1000000+option6*10000000+option7*100000000+option8*1000000000 pmem(250,pmemVal) end function GameHelper:LoadOptionsFromPMEM() local option1=1 local option2=1 local option3=2 local option4=2 local option5=1 local option6=1 local option7=0 local option8=1 Logger:Debug("LOADING BASE OPTIONS",glMsgType.INIT_BASE) local pmemVal=pmem(252) Logger:Info("Loaded options variable:"..pmemVal..";in pmem:252",glMsgType.INIT_BASE) if pmemVal==0 then return end option1=pmemVal%10 pmemVal=pmemVal-option1 Logger:Debug(" option1:"..option1,glMsgType.INIT_BASE) option2=pmemVal%100 pmemVal=pmemVal-option2 option2=math.floor(option2/10) Logger:Debug(" option2:"..option2,glMsgType.INIT_BASE) option3=pmemVal%10000 pmemVal=pmemVal-option3 option3=option3/1000 Logger:Debug(" option3:"..option3,glMsgType.INIT_BASE) option4=pmemVal%1000000 pmemVal=pmemVal-option4 option4=option4/100000 Logger:Debug(" option4:"..option4,glMsgType.INIT_BASE) option5=pmemVal%10000000 pmemVal=pmemVal-option5 option5=math.floor(option5/1000000) Logger:Debug(" option5:"..option5,glMsgType.INIT_BASE) option6=pmemVal%100000000 pmemVal=pmemVal-option6 option6=math.floor(option6/10000000) Logger:Debug(" option6:"..option6,glMsgType.INIT_BASE) option7=pmemVal%1000000000 pmemVal=pmemVal-option7 option7=math.floor(option7/100000000) Logger:Debug(" option7:"..option7,glMsgType.INIT_BASE) option8=pmemVal%10000000000 pmemVal=pmemVal-option8 option8=math.floor(option8/1000000000) Logger:Debug(" option8:"..option8,glMsgType.INIT_BASE) AIHelper.AIDifficulty=option1 GameHelper.gameModeDifficulty=option2 GameHelper.delayBeforeShowingFullCard=option3 GameHelper.delayBeforeShowingTooltips=option4 GameHelper.animationSpeed=option5 AIHelper.AISpeedMult=option6 AIHelper.aiTimeBetweenActionsInSecs=1-(AIHelper.AISpeedMult-2)*0.5 AIHelper.aiMaxTimeForTurnInSecs=AIHelper.aiTimeBetweenActionsInSecs*8+0.6 GameHelper.controlScheme=option8 and option8 or 1 end function GameHelper:ShuffleDeck(deck) local t=deck local j for i = #t, 2, -1 do j = math.random( i ) t[i], t[j] = t[j], t[i] end return t end function GameHelper:EndTurn() Logger:Debug("Ending turn",glMsgType.GAME_LOGIC) StateHelper.CleanPlayerMouseSelection() SfxHelper:PlaySFX(glSFXEndOfTurn,nil,36) if not GameHelper.isPlayerTurn then glEndTurnButton:makeVisible() else SfxHelper:PlaySFX(glSFXEndTurnData.id,glSFXEndTurnData.noteDef,-1) glEndTurnButton:visible(false) --to make button disappear when enemy turn if glEndTurnButton then ParticleHelper:CreateDeathFX(glEndTurnButton:getCenterX(),glEndTurnButton:getCenterY(),0) end end AIHelper.turnFinished=false if GameHelper.tutorialPhase>0 then if GameHelper.tutorialPhase<35 then GameHelper.endTurnButtonClicked=false if GameHelper.isPlayerTurn then GameHelper.isPlayerTurn=false if GameHelper.tutorialPhase>10 and GameHelper.tutorialPhase<30 then GameHelper.enemyLeaderCard.stats.attacksAvail.cur=1 GameHelper.playerLeaderCard.stats.attacksAvail.cur=1 foreach(GameHelper.playerBattlefieldCards,function(cardObj) cardObj.stats.attacksAvail.cur=1 end) elseif GameHelper.tutorialPhase>30 then local newTurnLeader=GameHelper.enemyLeaderCard newTurnLeader.stats.manaCount.max=math.min(RuleHelper.maxManaCount,newTurnLeader.stats.manaCount.max+1) newTurnLeader:RestoreMana() if GameHelper.tutorialPhase==34 then GameHelper.tutorialPhase=35 AsyncQueueLogicHelper:AddToQueue(function(data) glTutorialIsBlockingGUI=true glTutorialDialog=GUIHelper:CreateTutorialDialog(function(ref) glTutorialIsBlockingGUI=false end,{"Now you can decide between","diffrent units to summon.","It's up to you!","","^14Kill enemy leader before yours dies!"}) end,{},3) end end else --clean ai AIHelper.stopUpdatingAI=false AIHelper.aiTurnTimeCur=0 AIHelper.aiDelayBeforeTurn=0 AIHelper.aiDelayBeforeTurn=AIHelper.aiDelayBeforeTurnAmount AIHelper.aiTurnTimeOfNextAction=AIHelper.aiTimeBetweenActionsInSecs GameHelper.isPlayerTurn=true AIHelper.turnFinished=false if GameHelper.tutorialPhase<20 then AsyncQueueLogicHelper:AddToQueue(function(data) glTutorialDialog:hide() glTutorialDialog:remove() GameHelper.playerLeaderCard.stats.attacksAvail.cur=1 glTutorialIsBlockingGUI=true glTutorialDialog=GUIHelper:CreateTutorialDialog(function(ref) glTutorialIsBlockingGUI=false end,{"^14Anything you can use will have","^14green border around it.","^15Look, your unit is now ready to attack.","^14To attack enemy, click on your unit","and then click on enemy."}) end,{},0) elseif GameHelper.tutorialPhase==21 then glTutorialDialog:hide() glTutorialDialog:remove() local tutFunc3=function(ref) glTutorialDialog:hide() glTutorialDialog:remove() GameHelper:ExecuteDrawCard(true) GameHelper.playerLeaderCard.stats.manaCount.cur=1 GameHelper.playerLeaderCard.stats.manaVisualCount.cur=1 glTutorialIsBlockingGUI=false end local tutFunc2=function(ref) glTutorialDialog:hide() glTutorialDialog:remove() glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc3,{"^14To summon unit click on the drawn card","^14and click one of highlighted spaces."}) end local tutFunc1=function(ref) glTutorialIsBlockingGUI=false glTutorialDialog:hide() glTutorialDialog:remove() GameHelper.tutorialPhase=22 glTutorialIsBlockingGUI=true glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc2,{"To win this you have to use other units.","Which means drawing and playing cards!", "^14You draw one card","at the start of your turns."}) end glEndTurnButton:visible(false) glTutorialIsBlockingGUI=true glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc1,{"When your turn ends enemy turn starts.","Enemy can do the same actions as you!"}) elseif GameHelper.tutorialPhase==22 then local tutFunc1=function(ref) glTutorialDialog:hide() glTutorialDialog:remove() GameHelper.tutorialPhase=23 GameHelper.playerLeaderCard.stats.attacksAvail.cur=1 foreach(GameHelper.playerBattlefieldCards,function(card) if card then card.stats.attacksAvail.cur=1 end end) glTutorialIsBlockingGUI=false end glTutorialIsBlockingGUI=true glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc1,{"Now that turn has passed,","^14new unit is ready to attack!","^15Kill the enemy leader!"}) end end return end if GameHelper.tutorialPhase>43 then glEndTurnButton:visible(false) end end local newTurnLeader=GameHelper.isPlayerTurn and GameHelper.enemyLeaderCard or GameHelper.playerLeaderCard GameHelper.currentTurnLeader=newTurnLeader --TODO: move to startturn function so events can know what happens newTurnLeader.stats.manaCount.max=math.min(RuleHelper.maxManaCount+(table.contains(newTurnLeader.artifactsIDList,"MORE_MANA") and 1 or 0),newTurnLeader.stats.manaCount.max+(table.contains(newTurnLeader.artifactsIDList,"TWO_MANA_PER_TURN") and 2 or 1)) AsyncQueueLogicHelper:AddToQueue(function(data) newTurnLeader:RestoreMana() end,{},0.4) GameHelper.cardGUIElemSelected=nil GameHelper.cardGUIElemSelected1st=nil if GameHelper.tutorialPhase>0 and (GameHelper.tutorialPhase==41 or GameHelper.tutorialPhase==42) then if GameHelper.playerLeaderCard.stats.manaCount.max==2 then if GameHelper.tutorialPhase==41 then GameHelper.tutorialPhase=42 local tutFunc2=function(ref) glTutorialDialog:hide() glTutorialDialog:remove() GameHelper.tutorialPhase=43 glTutorialIsBlockingGUI=false for i = 1, (#GUIHelper.playerHandCards), 1 do local card=GUIHelper.playerHandCards[i] end end local tutFunc1_5=function(ref) glTutorialDialog:hide() glTutorialDialog:remove() glEndTurnButton:visible(false) glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc2,{"It has special power called DISTRACT","^14To learn about power(s) on any card","^14you have to hover with your mouse","^14over that card for a few seconds.","","Will wait for you till you do that."}) end newTurnLeader.stats.manaCount.cur=0 newTurnLeader.stats.manaVisualCount.cur=0 glEndTurnButton:visible(false) glTutorialIsBlockingGUI=true AsyncQueueLogicHelper:AddToQueue(function(data) glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc1_5,{"Have you looked at your cards below?","Those units that require 2 MANA.","Let's look at what that unit does.",}) end,{},1) end end end if (not GameHelper.isPlayerTurn) and GameHelper.tutorialPhase==47 and GameHelper.playerLeaderCard.stats.manaCount.max==6 then GameHelper.tutorialPhase=48 GameHelper.playerLeaderCard.stats.manaCount.cur=0 GameHelper.playerLeaderCard.stats.manaVisualCount.cur=0 glEndTurnButton:visible(false) local n=#GameHelper.playerDeckCards for i=1,n do table.remove(GameHelper.playerDeckCards) end table.insert(GameHelper.playerDeckCards,deepcopy(GameHelper.allCards.TUTORIAL3)) table.insert(GameHelper.playerDeckCards,deepcopy(GameHelper.allCards.TUTORIAL1)) table.insert(GameHelper.playerDeckCards,deepcopy(GameHelper.allCards.TUTORIAL1)) table.insert(GameHelper.playerDeckCards,deepcopy(GameHelper.allCards.TUTORIAL1)) local tutFunc2=function(ref) glTutorialDialog:hide() glTutorialDialog:remove() glEndTurnButton:visible(false) glTutorialIsBlockingGUI=false end local tutFunc1=function(ref) AsyncQueueLogicHelper:AddToQueue(function() glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc2,{"^14SPELLS are one time use cards","^14that can be applied on units","Hover over it to learn more!", "", "Game is paused until then."}) end,{},1) end glTutorialIsBlockingGUI=true AsyncQueueLogicHelper:AddToQueue(function() GameHelper.playerLeaderCard.stats.manaCount.cur=0 GameHelper.playerLeaderCard.stats.manaVisualCount.cur=0 glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc1,{"Hey look!","","You just drawn SPELL type of card!"}) end,{},1) end if (not GameHelper.isPlayerTurn) and GameHelper.tutorialPhase==49 and GameHelper.playerLeaderCard.stats.manaCount.max==7 then GameHelper.playerLeaderCard.stats.manaCount.cur=0 GameHelper.playerLeaderCard.stats.manaVisualCount.cur=0 glEndTurnButton:visible(false) local tutFunc2=function(ref) glTutorialDialog:hide() glTutorialDialog:remove() GameHelper.playerLeaderCard.stats.manaCount.cur=7 GameHelper.playerLeaderCard.stats.manaVisualCount.cur=7 glEndTurnButton:makeVisible() glTutorialIsBlockingGUI=false end local tutFunc1=function(ref) glTutorialDialog:hide() glTutorialDialog:remove() glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc2,{"Let's kill that enemy with their own weapon!","Summon that snake!",}) end glTutorialIsBlockingGUI=true AsyncQueueLogicHelper:AddToQueue(function() glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc1,{"^15As you saw, ARMOR stopped VENOM TAG, why?","^14Because as TAG description says","^14it requires doing DMG to HP","^14And ARMOR is always damaged first.","^15ARMOR allows to dodge a few nasty tricks!"}) end,{},1) end Logger:Info("----------------",glMsgType.GAME_LOGIC) Logger:Info("Turn ("..GameHelper.turnCounter..") started for "..(GameHelper.isPlayerTurn and "ENEMY" or "PLAYER"),glMsgType.GAME_LOGIC) --clean ai AIHelper.aiTurnTimeCur=0 AIHelper.aiDelayBeforeTurn=0 AIHelper.aiDelayBeforeTurn=AIHelper.aiDelayBeforeTurnAmount AIHelper.aiTurnTimeOfNextAction=AIHelper.aiTimeBetweenActionsInSecs AIHelper:SetMoveDesc("") AIHelper.doNothingCounter=0 --reset units local unitsToReset={} table.insert(unitsToReset,GameHelper.playerLeaderCard) table.insert(unitsToReset,GameHelper.enemyLeaderCard) foreach(GameHelper.playerBattlefieldCards,function(card) if card then table.insert(unitsToReset,card) end end) foreach(GameHelper.enemyBattlefieldCards,function(card) if card then table.insert(unitsToReset,card) end end) Logger:Debug("unitsToReset:"..(#unitsToReset),glMsgType.GAME_LOGIC) foreach(unitsToReset,function(card) if card then local cardGUI=nil foreach(GUIHelper.playerBattlefieldCards,function(g) if not cardGUI and g.cardObj and g.cardObj==card then cardGUI=g end end) foreach(GUIHelper.enemyBattlefieldCards,function(g) if not cardGUI and g.cardObj and g.cardObj==card then cardGUI=g end end) if not cardGUI then if card.isLeaderCard then if card.isPlayerCard then cardGUI=glPlayerLeaderCardGUI else cardGUI=glEnemyLeaderCardGUI end end end card.stats.attacksAvail:setToMax() card.stats.turnsAlive:incr() if cardGUI then cardGUI.x=cardGUI.origX cardGUI.y=cardGUI.origY for i=1,(card.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=card.tags[i] if tag then if tag.funcOnEveryTurnEnd then tag:funcOnEveryTurnEnd(card,cardGUI) end if tag.funcOnUnitTurnEnd and ((cardGUI.isPlayerCard and GameHelper.isPlayerTurn) or (not cardGUI.isPlayerCard and not GameHelper.isPlayerTurn)) then tag:funcOnUnitTurnEnd(card,cardGUI) end if tag.funcOnEveryTurnStart then tag:funcOnEveryTurnStart(card,cardGUI) end if tag.funcOnUnitTurnStart and ((cardGUI.isPlayerCard and not GameHelper.isPlayerTurn) or (not cardGUI.isPlayerCard and GameHelper.isPlayerTurn)) then tag:funcOnUnitTurnStart(card,cardGUI) end end end cardGUI.border=glGUIFrameStyleUnusableCard.border end end end) foreach(GUIHelper.playerHandCards,function(cardGUI) if cardGUI and cardGUI.cardObj then cardGUI.border=glGUIFrameStyleUnusableCard.border end end) GameHelper.currentGameState=glGameStates.START_TURN EventHelper:ExecuteEvent(glEventTypes.TURN_ENDED,self,false,{forPlayer=GameHelper.isPlayerTurn}) GameHelper.isPlayerTurn=not GameHelper.isPlayerTurn AsyncQueueLogicHelper:AddToQueue(function(data) GameHelper:ExecuteDrawCard(data.isPlayerCard) end,{isPlayerCard=GameHelper.isPlayerTurn},(GameHelper.isPlayerTurn and 0.5 or 0)) return true end function GameHelper:ApplyBuffTo(cardObj,selCardGUI,buffType,value,delayForFX,simulateOnly) if not cardObj then return end if not value or value==0 then Logger:Error("Tried to apply BUFF:"..buffType..";for:"..cardObj.id..";for:"..(cardObj.isPlayerCard and "PLAYER" or "ENEMY").."; BUT VALUE of buff is:"..(value and value or "NIL"),glMsgType.GAME_LOGIC) return false end if not simulateOnly then Logger:Debug("Applying BUFF:"..buffType..";value:"..value..";for:"..cardObj.id..";for:"..(cardObj.isPlayerCard and "PLAYER" or "ENEMY"),glMsgType.GAME_LOGIC) end local stats=cardObj.stats buffType=string.lower(buffType) if buffType=="hp" then stats.hp.max=stats.hp.max+value stats.hp:add(value) elseif buffType=="atk" or buffType=="inspired" then stats.attack.max=stats.attack.max+value stats.attack:add(value) elseif buffType=="armor" then stats.armor.max=stats.armor.max+value stats.armor:add(value) elseif buffType=="mana" then if not simulateOnly then stats.manaCount.max=stats.manaCount.max+value if cardObj.isLeaderCard then cardObj:RestoreMana(value,simulateOnly) else stats.manaCount:add(value) end end elseif buffType=="spellpwr" then stats.spellPower.max=stats.spellPower.max+value stats.spellPower:add(value) end if not simulateOnly then if selCardGUI then if buffType=="hp" then ParticleHelper:CreateHPBuffFX(selCardGUI:getCenterX(),selCardGUI:getCenterY(),delayForFX) GUIHelper:DrawChangeIndicator(selCardGUI,"HP",value,delayForFX) elseif buffType=="atk" or buffType=="inspired" then ParticleHelper:CreateATKBuffFX(selCardGUI:getCenterX(),selCardGUI:getCenterY(),delayForFX) GUIHelper:DrawChangeIndicator(selCardGUI,"ATK",value,delayForFX) elseif buffType=="armor" then ParticleHelper:CreateArmorBuffFX(selCardGUI:getCenterX(),selCardGUI:getCenterY(),delayForFX) GUIHelper:DrawChangeIndicator(selCardGUI,"ARMOR",value,delayForFX) elseif buffType=="mana" then ParticleHelper:CreateManaBuffFX(selCardGUI:getCenterX(),selCardGUI:getCenterY(),delayForFX) elseif buffType=="spellpwr" then ParticleHelper:CreateSpellPWRBuffFX(selCardGUI:getCenterX(),selCardGUI:getCenterY(),delayForFX) end end end end function GameHelper:ApplyCutTo(cardObj,selCardGUI,buffType,value,delayForFX,simulateOnly) if not cardObj then return end if not value or value==0 then Logger:Error("Tried to apply CUT:"..buffType..";for:"..cardObj.id..";for:"..(cardObj.isPlayerCard and "PLAYER" or "ENEMY").."; BUT VALUE of buff is:"..(value and value or "NIL"),glMsgType.GAME_LOGIC) return false end Logger:Debug("Applying CUT:"..buffType..";value:"..value..";for:"..cardObj.id..";for:"..(cardObj.isPlayerCard and "PLAYER" or "ENEMY"),glMsgType.GAME_LOGIC) local stats=cardObj.stats buffType=string.lower(buffType) if buffType=="hp" then stats.hp.max=stats.hp.max-value stats.hp:sub(value) if stats.hp.cur<=0 then --TODO: this is copy from applydamageto, move to func and get more tokens if selCardGUI then for i=1,(cardObj.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=cardObj.tags[i] if tag and tag.funcOnOwnedUnitBeingKilled then tag:funcOnOwnedUnitBeingKilled(cardObj,nil,cardObj.cardGUI,nil,simulateOnly) end end end EventHelper:ExecuteEvent(glEventTypes.UNIT_DIED,(selCardGUI and selCardGUI.id or "KILL_SPELL_CUT"),simulateOnly,{cardObj=cardObj,initingObj=(selCardGUI and selCardGUI.cardObj or selCardGUI),typeOfDeath=glUnitDeathTypes.CASTED_SPELL}) GameHelper:DestroyUnit(cardObj,cardObj.cardGUI,delayForFX+0.3,simulateOnly) end elseif buffType=="atk" or buffType=="inspired" then stats.attack.max=stats.attack.max-value stats.attack:sub(value) elseif buffType=="armor" then stats.armor.max=stats.armor.max-value stats.armor:sub(value) elseif buffType=="mana" then if not simulateOnly then stats.manaCount.max=stats.manaCount.max-value if cardObj.isLeaderCard then cardObj:SpendMana(value,simulateOnly) else stats.manaCount:sub(value) end end elseif buffType=="spellpwr" then stats.spellPower.max=stats.spellPower.max-value stats.spellPower:sub(value) end if not simulateOnly then if selCardGUI then if buffType=="ehp" then ParticleHelper:CreateHPCutFX(selCardGUI:getCenterX(),selCardGUI:getCenterX(),delayForFX) GUIHelper:DrawChangeIndicator(selCardGUI,"HP",-value,delayForFX) elseif buffType=="atk" or buffType=="inspired" then ParticleHelper:CreateATKCutFX(selCardGUI:getCenterX(),selCardGUI:getCenterY(),delayForFX) GUIHelper:DrawChangeIndicator(selCardGUI,"ATK",-value,delayForFX) elseif buffType=="armor" then ParticleHelper:CreateArmorCutFX(selCardGUI:getCenterX(),selCardGUI:getCenterY(),delayForFX) GUIHelper:DrawChangeIndicator(selCardGUI,"ARMOR",-value,delayForFX) elseif buffType=="mana" then ParticleHelper:CreateManaCutFX(selCardGUI:getCenterX(),selCardGUI:getCenterY(),delayForFX) elseif buffType=="spellpwr" then ParticleHelper:CreateSpellPWRCutFX(selCardGUI:getCenterX(),selCardGUI:getCenterY(),delayForFX) end end end end function GameHelper:ApplyHealTo(cardObj,selCardGUI,value,delayForFX,simulateOnly) if not value or value==0 then return false end local statsCard=cardObj.stats local oldHP=statsCard.hp.cur statsCard.hp:add(value) local diff=(statsCard.hp.cur-oldHP) if not simulateOnly and diff>0 and selCardGUI then ParticleHelper:CreateHealingFX(selCardGUI:getCenterX(),selCardGUI:getCenterY(),delayForFX) GUIHelper:DrawChangeIndicator(selCardGUI,"HP",diff,delayForFX) end return true end function GameHelper:ApplyHPDamageTo(cardObj,selCardGUI,attackingCardGUI,value,delayForFX,simulateOnly) if value==0 then return false end local statsCard=cardObj.stats local cardArmor=statsCard.armor.cur statsCard.hp:sub(value) if not simulateOnly and selCardGUI then EventHelper:ExecuteEvent(glEventTypes.DAMAGE_DEALT,(attackingCardGUI and attackingCardGUI.id or "ApplyDamageTo()"),simulateOnly,{amountDealt=value,cardObj=cardObj,initingObj=(attackingCardGUI and attackingCardGUI.cardObj or nil)}) --TODO: create something helper that ties sound and fx together AsyncQueueLogicHelper:AddToQueue(function(data) SfxHelper:PlaySFX(glSFXHPDamageData.id,glSFXHPDamageData.noteDef) end,{},delayForFX) if selCardGUI then ParticleHelper:CreateWoundedFX(selCardGUI.x+8,selCardGUI:getCenterY(),selCardGUI.pos,selCardGUI.isPlayerCard and 1 or 0,((statsCard.hp.cur<=statsCard.hp.min) and 10 or value),(attackingCardGUI and {x1=attackingCardGUI.x,x2=attackingCardGUI:getRightX(),y1=attackingCardGUI.y,y2=attackingCardGUI:getDownY()} or nil),(string.sub(cardObj.id,1,1)=="U" and 5 or 6),delayForFX) GUIHelper:DrawDamageIndicator(selCardGUI,attackingCardGUI,value,"HP",delayForFX+0.2) end end if not statsCard.hp:aboveMin() then local attackingCardObj=(attackingCardGUI and attackingCardGUI.cardObj or nil) EventHelper:ExecuteEvent(glEventTypes.UNIT_DIED,(selCardGUI and selCardGUI.id or "KILL_SPELL_DMG"),simulateOnly,{cardObj=cardObj,initingObj=attackingCardObj,typeOfDeath=((attackingCardObj and attackingCardObj.isSpell) and glUnitDeathTypes.CASTED_SPELL or glUnitDeathTypes.ATTACKED_BY_UNIT)})--selCardGUI.isPlayerCard and GameHelper.playerLeaderCard or GameHelper.enemyLeaderCard,typeOfDeath=glUnitDeathTypes.CASTED_SPELL}) self:DestroyUnit(cardObj,selCardGUI,delayForFX+0.3,simulateOnly) if attackingCardGUI then for i=1,(cardObj.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=cardObj.tags[i] if tag and tag.funcOnOwnedUnitBeingKilled then tag:funcOnOwnedUnitBeingKilled(cardObj,attackingCardGUI,cardObj.cardGUI,attackingCardGUI.cardGUI,simulateOnly) end end end end end function GameHelper:ApplyDamageTo(cardObj,selCardGUI,attackingCardGUI,value,delayForFX,simulateOnly) if value==0 then return false end local statsCard=cardObj.stats local cardArmor=statsCard.armor.cur if not simulateOnly then if value>8 then glScreenShakeVal=30 elseif value>4 then glScreenShakeVal=10 end end local startVal=value if cardArmor>0 then GUIHelper:DrawDamageIndicator(selCardGUI,attackingCardGUI,math.min(statsCard.armor.cur,value),"ARMOR",delayForFX) statsCard.armor:sub(value) if not simulateOnly then AsyncQueueLogicHelper:AddToQueue(function(data) SfxHelper:PlaySFX(glSFXArmorDamageData.id,glSFXArmorDamageData.noteDef) end,{},delayForFX) if selCardGUI then ParticleHelper:CreateArmorDamagedFX(selCardGUI.x+8,selCardGUI:getCenterY(),delayForFX) end end value=math.max(0,value-cardArmor) end if value>0 then GameHelper:ApplyHPDamageTo(cardObj,selCardGUI,attackingCardGUI,value,delayForFX,simulateOnly) else end EventHelper:ExecuteEvent(glEventTypes.DAMAGE_DEALT,(attackingCardGUI and attackingCardGUI.id or "ApplyDamageTo()"),simulateOnly,{amountDealt=startVal-value,cardObj=cardObj,initingObj=(attackingCardGUI and attackingCardGUI.cardObj or nil)}) return true end function GameHelper:SummonUnitOntoBattlefield(cardObj,pos,isPlayerCard) local cardGUI=(isPlayerCard and GUIHelper.playerBattlefieldCards or GUIHelper.enemyBattlefieldCards)[pos] if not cardGUI then return false end cardObj.cardGUI=cardGUI cardObj.isPlayerCard=isPlayerCard cardGUI.delayBeforeVisible=0.5 cardGUI:visible(false) for i=1,(cardObj.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=cardObj.tags[i] if tag and tag.funcBeforeBeingSummoned then tag:funcBeforeBeingSummoned(cardObj,cardGUI) end end if isPlayerCard and GameHelper.tutorialPhase>0 and (GameHelper.tutorialPhase>43 or GameHelper.tutorialPhase==22) then glEndTurnButton:makeVisible() end local battlefield=(isPlayerCard and GameHelper.playerBattlefieldCards or GameHelper.enemyBattlefieldCards) battlefield[pos]=cardObj AsyncQueueLogicHelper:AddToQueue(function(data) local spellTypeData=glSFXSummonBeastUnitData local t=cardObj.id if string.sub(t,1,1)=="H" then spellTypeData=glSFXSummonHumanUnitData elseif string.sub(t,1,1)=="U" then spellTypeData=glSFXSummonUndeadUnitData end SfxHelper:PlaySFX(spellTypeData.id,spellTypeData.noteDef) data.cardGUI:visible(true) end,{cardGUI=cardGUI},delayForFX+0.5) if cardGUI then ParticleHelper:CreateSummoningUnitFX(cardGUI:getCenterX(),cardGUI.y+(isPlayerCard and cardGUI.h-2 or 2)) ParticleHelper:CreateSummoningUnitFX(cardGUI:getCenterX(),cardGUI.y+(isPlayerCard and cardGUI.h-8 or 8)) ParticleHelper:CreateSummoningUnitFX(cardGUI:getCenterX(),cardGUI.y+(isPlayerCard and cardGUI.h-14 or 14)) end for i=1,(cardObj.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=cardObj.tags[i] if tag and tag.funcAfterBeingSummoned then tag:funcAfterBeingSummoned(cardObj) end end --TODO: give funcOnOtherUnitBeingSummoned to units from other sides as at some points tags may need it! foreach(GameHelper.playerBattlefieldCards,function(battleCardObj) for i=1,(battleCardObj.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=battleCardObj.tags[i] if tag and tag.funcOnOtherUnitBeingSummoned and cardObj~=battleCardObj then tag:funcOnOtherUnitBeingSummoned(battleCardObj,battleCardObj.cardGUI,cardObj,cardGUI,simulateOnly) end end end) --player leader for i=1, RuleHelper.numberOfActiveTagsInLeader do local tag=GameHelper.playerLeaderCard.tags[i] if tag and tag.funcOnOtherUnitBeingSummoned and cardObj~=GameHelper.playerLeaderCard then tag:funcOnOtherUnitBeingSummoned(GameHelper.playerLeaderCard,GameHelper.playerLeaderCard.cardGUI,cardObj,cardGUI,simulateOnly) end end foreach(GameHelper.enemyBattlefieldCards,function(battleCardObj) for i=1,(battleCardObj.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=battleCardObj.tags[i] if tag and tag.funcOnOtherUnitBeingSummoned and cardObj~=battleCardObj then tag:funcOnOtherUnitBeingSummoned(battleCardObj,battleCardObj.cardGUI,cardObj,cardGUI,simulateOnly) end end end) -- enemy leader for i=1,RuleHelper.numberOfActiveTagsInLeader do local tag=GameHelper.enemyLeaderCard.tags[i] if tag and tag.funcOnOtherUnitBeingSummoned and cardObj~=GameHelper.enemyLeaderCard then tag:funcOnOtherUnitBeingSummoned(GameHelper.enemyLeaderCard,GameHelper.enemyLeaderCard.cardGUI,cardObj,cardGUI,simulateOnly) end end local units=GameHelper:GetAdjacentUnitsToProvided((isPlayerCard and GameHelper.playerBattlefieldCards or GameHelper.enemyBattlefieldCards),cardObj) if GameHelper.tutorialPhase>0 and GameHelper.tutorialPhase==32 then GameHelper.tutorialPhase=33 AsyncQueueLogicHelper:AddToQueue(function(data) glTutorialDialog=GUIHelper:CreateTutorialDialog(function(ref) GameHelper.tutorialPhase=34 if glEnemyToolbar then ParticleHelper:CreateSummoningUnitFX(glEnemyToolbar:getCenterX()+70,glEnemyToolbar:getCenterY()) end glPlayerToolbarMana:makeVisible() glEnemyToolbarMana:makeVisible() AsyncQueueLogicHelper:AddToQueue(function(data) glTutorialDialog=GUIHelper:CreateTutorialDialog(function(ref) glEndTurnButton:makeVisible() if glEndTurnButton then ParticleHelper:CreateSummoningUnitFX(glEndTurnButton:getCenterX(),glEndTurnButton:getCenterY()) end end,{"Now you can end your first turn","and wait for the next one.","","^14Every turn each player get one *max* MANA,","^14up to 9, and regenerate all points up to","^14their current max amount."})end,{},2) end,{"^14Of course enemy has their own","^14mana counter just like you."})end,{},3) end EventHelper:ExecuteEvent(glEventTypes.UNIT_SUMMONED,self,simulateOnly,{cardObj=cardObj,isPlayer=cardObj.isPlayerCard,isLeader=cardObj.isLeaderCard}) return cardObj end function GameHelper:DestroyUnit(cardObj,selCardGUI,delayForFX,simulateOnly) if cardObj.isDeleted then return false end if not simulateOnly then if selCardGUI then ParticleHelper:CreateWoundedFX(selCardGUI.x+8,selCardGUI:getCenterY(),selCardGUI.pos,selCardGUI.isPlayerCard and 1 or 0,3,nil,(string.sub(cardObj.id,1,1)=="U" and 5 or 6),delayForFX+0.25) ParticleHelper:CreateWoundedFX(selCardGUI.x+8,selCardGUI:getCenterY(),selCardGUI.pos,selCardGUI.isPlayerCard and 1 or 0,2,nil,(string.sub(cardObj.id,1,1)=="U" and 5 or 6),delayForFX+0.29) end if cardObj.isLeaderCard and table.contains(cardObj.artifactsIDList,"REVIVE_ANKH") then local i=-1 for j=1,#cardObj.artifactsIDList do if cardObj.artifactsIDList[j]=="REVIVE_ANKH" then i=j break end end if i>0 then table.remove(cardObj.artifactsIDList,i) GameHelper:ApplyHealTo(cardObj,cardObj.cardGUI,cardObj.stats.hp.max,0.2,simulateOnly) end return end end for i=1,(cardObj.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=cardObj.tags[i] if tag and tag.funcOnUnitDestroy then tag:funcOnUnitDestroy(cardObj,selCardGUI,simulateOnly) end end cardObj.isDeleted=true local statsCard=cardObj.stats statsCard.hp:setToMin() if not simulateOnly then AsyncQueueLogicHelper:AddToQueue(function(data) SfxHelper:PlaySFX(glSFXUnitDeathData.id,glSFXUnitDeathData.noteDef) end,{},delayForFX+0.45) if selCardGUI then ParticleHelper:CreateDeathFX(selCardGUI:getCenterX(),selCardGUI:getCenterY()-10,delayForFX+0.5) if not selCardGUI.isLeaderCard then AsyncQueueLogicHelper:AddToQueue(function(data) if data.cardGUI.isPlayerCard then GameHelper.playerBattlefieldCards[data.cardGUI.pos]=nil else GameHelper.enemyBattlefieldCards[data.cardGUI.pos]=nil local hasWeakZombieSummonArtifact=table.contains(GameHelper.playerLeaderCard.artifactsIDList,"SUMMON_WEAK_ZOMBIE") if hasWeakZombieSummonArtifact then local nOfZombieArtifacts=0 foreach(GameHelper.playerLeaderCard.artifactsIDList,function(name) if name=="SUMMON_WEAK_ZOMBIE" then nOfZombieArtifacts=nOfZombieArtifacts+1 end end) for z=1,nOfZombieArtifacts do local n=0 for i=1,6 do local bf=GameHelper.playerBattlefieldCards if not bf[i] then n=i break end end if n>0 then if not simulateOnly then local unit=GameHelper:SummonUnitOntoBattlefield(GameHelper.allCards["U025"]:DeepCopy(),n,true) if unit then local unitTag=deepcopy(glUnitTags["SUMMONED"]) unit:InsertTag(unitTag,simulateOnly) end end end end end end data.cardGUI.border=glGUIFrameStyleTotallyUnusableCard.border end,{cardGUI=selCardGUI},delayForFX+0.65) cardObj.cardGUI=nil end end end return true end function GameHelper:CastSpellAction(cardObj1st,selCardGUI1st, cardObj2nd,selCardGUI2nd,simulateOnly) if not simulateOnly then AsyncQueueLogicHelper:AddToQueue(function(data) local spellTypeData=glSFXCastBuffSpellData local t=cardObj1st.type if t=="DMG" then spellTypeData=glSFXCastDamageSpellData elseif t=="DEBUFF" then spellTypeData=glSFXCastDebuffSpellData elseif t=="SUMMON" then spellTypeData=glSFXCastSummonSpellData end SfxHelper:PlaySFX(spellTypeData.id,spellTypeData.noteDef) end,{},delayForFX) end for i=1,(cardObj1st.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=cardObj1st.tags[i] if tag and tag.funcOnCast then tag:funcOnCast(cardObj1st,cardObj2nd,selCardGUI1st,selCardGUI2nd,simulateOnly) end end EventHelper:ExecuteEvent(glEventTypes.SPELL_CASTED_ON,self,simulateOnly,{cardObj=cardObj2nd,initingObj=cardObj1st}) return true end function GameHelper:SimulateCastingSpellAction(cardObj1st, cardObj2nd) GameHelper:CastSpellAction(cardObj1st,nil, cardObj2nd,nil,true) end function GameHelper:SimulateAttackAction(cardObj1st, cardObj2nd) GameHelper:ExecuteAttackAction(cardObj1st,nil,cardObj2nd,nil,true) end function GameHelper:ExecuteAttackAction(cardObj1st,selCardGUI1st,cardObj2nd,selCardGUI2nd,simulateOnly) local statsCard1st=cardObj1st.stats local statsCard2nd=cardObj2nd.stats local card1stDMG=statsCard1st.attack.cur local card2ndDMG=statsCard2nd.attack.cur local card1stArmor=statsCard1st.armor.cur local card2ndArmor=statsCard2nd.armor.cur local highPriorityTags={} for i=1,(cardObj1st.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=cardObj1st.tags[i] if tag and tag.funcBeforeAttacking and tag.highPriority then table.insert(highPriorityTags,tag) end end for i=1,#highPriorityTags do local tag=highPriorityTags[i] tag:funcBeforeAttacking(cardObj1st,cardObj2nd,selCardGUI1st,selCardGUI2nd,simulateOnly) end for i=1,(cardObj1st.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=cardObj1st.tags[i] if tag and tag.funcBeforeAttacking and not tag.highPriority then tag:funcBeforeAttacking(cardObj1st,cardObj2nd,selCardGUI1st,selCardGUI2nd,simulateOnly) end end if not simulateOnly then GUIHelper.ShakeFrameControl(selCardGUI1st,4,0.2,0) if card1stDMG>0 and selCardGUI1st and selCardGUI2nd then AsyncQueueLogicHelper:AddToQueue(function(data) SfxHelper:PlaySFX(glSFXRangedAttackData.id,glSFXRangedAttackData.noteDef) end,{},delayForFX) end end self:ApplyDamageTo(cardObj2nd,selCardGUI2nd,selCardGUI1st,card1stDMG,0.2+0.05*(3-GameHelper.animationSpeed),simulateOnly) if not cardObj1st:GetTagByName(glUnitTags.RANGED.name) then -- if not simulateOnly and card2ndDMG>0 then GUIHelper.ShakeFrameControl(selCardGUI2nd,4,0.2,0.5) if card2ndDMG>0 and selCardGUI1st and selCardGUI2nd then AsyncQueueLogicHelper:AddToQueue(function(data) SfxHelper:PlaySFX(glSFXRangedAttackData.id,glSFXRangedAttackData.noteDef) end,{},delayForFX) end end self:ApplyDamageTo(cardObj1st,selCardGUI1st,selCardGUI2nd,card2ndDMG,0.7+0.1*(3-GameHelper.animationSpeed),simulateOnly) end statsCard1st.attacksAvail:decr() local highPriorityTags={} for i=1,(cardObj1st.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=cardObj1st.tags[i] if tag and tag.funcAfterAttacking and tag.highPriority then tag:funcAfterAttacking(cardObj1st,cardObj2nd,selCardGUI1st,selCardGUI2nd,simulateOnly) end end for i=1,#highPriorityTags do local tag=highPriorityTags[i] tag:funcAfterAttacking(cardObj1st,cardObj2nd,selCardGUI1st,selCardGUI2nd,simulateOnly) end for i=1,(cardObj1st.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=cardObj1st.tags[i] if tag and tag.funcAfterAttacking and not tag.highPriority then tag:funcAfterAttacking(cardObj1st,cardObj2nd,selCardGUI1st,selCardGUI2nd,simulateOnly) end end for i=1,(cardObj1st.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=cardObj1st.tags[i] if tag and tag.funcAfterAttacking then end end if not simulateOnly then Logger:Debug("phase:"..GameHelper.tutorialPhase,glMsgType.TUTORIAL) if GameHelper.tutorialPhase>0 and GameHelper.tutorialPhase==20 then local tutFunc2= function() glEndTurnButton:makeVisible() GameHelper.tutorialPhase=21 end AsyncQueueLogicHelper:AddToQueue( function(data) glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc2,{"Enemy leader has more HP,","^14and because it has 1 ATK","^14it will damage your unit back","when you attack it!"}) end,{},1.5) end end EventHelper:ExecuteEvent(glEventTypes.UNIT_WAS_ATTACKED,self,simulateOnly,{cardObj=cardObj2nd,initingObj=cardObj1st}) return true end function GameHelper:GetAdjacentUnitsToProvided(unitsTable,middleUnit) local includeLeader=true local units={} local iMin=0 local iMax=0 local foundLeader=false for i=1,7 do local unit=unitsTable[i] if middleUnit.isLeaderCard then iMin=2 iMax=6 break elseif unit==middleUnit then iMin=i-1 iMax=i+1 break end end foundLeader=(iMin>0 and iMax<7) if not middleUnit.isLeaderCard and includeLeader and foundLeader then table.insert(units,(middleUnit.isPlayerCard and GameHelper.playerLeaderCard or GameHelper.enemyLeaderCard)) end for j=iMin,iMax do local u=unitsTable[j] if u and u~=middleUnit then table.insert(units,u) end end return units end --TODO: force user to provide units to check to make it more agnostic? function GameHelper:FindAmountOfSpellPowerOnBattlefield(isPlayer) local modVal=0 if isPlayer then if table.contains(GameHelper.playerLeaderCard.artifactsIDList,"STRONGER_SPELLS") then modVal=1 end end foreach(self.playerBattlefieldCards,function(card) modVal=modVal+card.stats.spellPower.cur end) foreach(self.enemyBattlefieldCards,function(card) modVal=modVal+card.stats.spellPower.cur end) foreach({self.playerLeaderCard,self.enemyLeaderCard},function(card) modVal=modVal+card.stats.spellPower.cur end) return modVal end function GameHelper:InitSpellCardStatsTable(manaCost,spellPower) return { manaCost=self:InitAttributeTable("manaCost",0,99,manaCost), spellPower=self:InitAttributeTable("spellPower",0,99,spellPower), } end function GameHelper:InitUnitCardStatsTable(hp,armor,attack,manaCost) return { hp=self:InitAttributeTable("hp",0,hp,hp), armor=self:InitAttributeTable("armor",0,armor,armor), attack=self:InitAttributeTable("attack",0,attack,attack), manaCost=self:InitAttributeTable("manaCost",0,10,manaCost), attacksAvail=self:InitAttributeTable("attacksAvail",0,1,0), turnsAlive=self:InitAttributeTable("turnsAlive",0,999999,0), spellPower=self:InitAttributeTable("spellPower",-99,99,0), } end function GameHelper:InitLeaderCardStatsTable(hp,armor,attack) local stats=self:InitUnitCardStatsTable(hp,armor,attack,0) stats["manaCount"]=GameHelper:InitAttributeTable("manaCount",0,0,0) stats["manaVisualCount"]=GameHelper:InitAttributeTable("manaVisualCount",0,0,0) stats["pointsToAllocate"]=GameHelper:InitAttributeTable("pointsToAllocate",0,99,0) return stats end function GameHelper:InitAttributeTable(name,min,max,cur,isFloat) return {name=name,min=min,max=max,cur=cur, isFloat=isFloat, add=function(self,val) self.cur=math.max(self.min,math.min(self.cur+val,self.max)) return self.cur end, sub=function(self,val) self:add(-val) end, incr=function(self) self:add(1) return self.cur end, decr=function(self) self:add(-1) return self.cur end, mult=function(self,val) self:set(self.cur*val) return self.cur end, div=function(self,val) self:set(self.cur/val) return self.cur end, set=function(self,val) self.cur=math.max(math.min(val,self.max),self.min) if not self.isFloat then self.cur=math.floor(self.cur) end return self.cur end, setToMin=function(self) self:set(self.min) return self.cur end, setToMax=function(self) self:set(self.max) return self.cur end, percent=function(self) return self.cur/self.max end, aboveMin=function(self) return self.cur>self.min end, belowMax=function(self) return self.cur=track.length then self:TurnMusicOff() end else self:TurnMusicOn() end end function MusicHelper:TurnMusicOff() music() self.playing=false local track=self.tracks[self.trackID] if track then track.currentTime=0 end Logger:Info("Music stopped",glMsgType.MUSIC) end -- GUICREATOR CLASS GUICreator = {} GUICreator.__index = GUICreator GUICreator.id=0 function GUICreator:CreateBattlefieldScreen() if glPlayerToolbar then Logger:Error("BATTLEFIELD screen already exists!",glMsgType.GUI) end Logger:Debug("Creating BATTLEFIELD screen",glMsgType.GUI) glGameOptionsButton=GUIHelper:CreateGUIFrame("glGameOptionsButton",-1,46,17,17,nil) glGameOptionsButton.colors = {7,7,10} glGameOptionsButton.border = { colors = {2,2,2}, width = 1, } glGameOptionsButton:Content(function(ref,x,y) spr(268,x-1,y,0,1,0,0,2,2) end) glGameOptionsButton.onCleanRelease=function(ref) if glGameOptionsButton:visible() then GUIHelper.InteractableActiveControlBaseClickFunc(ref) GUIHelper.gameOptionsButtonClicked=true end GUIHelper.InteractableActiveControlBaseClickFunc(ref) end glGameOptionsButton.controlName="OPTIONS" glGameOptionsButton.tooltipTexts=glTooltipsStrings.buttonOptions glGameOptionsButton.onHover=function(ref) if ref:visible() then GUIHelper.controlHoveredOver=ref GameHelper.cardGUIElemHoveredOver=nil end end glEndTurnButton=GUIHelper:CreateGUIFrame("glEndTurnButton",225,46,17,17,nil) glEndTurnButton.colors = {7,7,10} glEndTurnButton.border = { colors = {2,2,2}, width = 1, } glEndTurnButton:Content(function(ref,x,y) spr(270,x,y,0,1,0,0,2,2) end) glEndTurnButton.tooltipTexts=glTooltipsStrings.buttonEndTurn glEndTurnButton.controlName="END TURN" glEndTurnButton.onHover=function(ref) if ref:visible() then GUIHelper.controlHoveredOver=ref GameHelper.cardGUIElemHoveredOver=nil end end glEndTurnButton.onCleanRelease=function(ref) if glEndTurnButton:visible() then GUIHelper.InteractableActiveControlBaseClickFunc(ref) GUIHelper.endTurnButtonClicked=true end end glEnemyToolbar=GUIHelper:CreateGUIFrame("glEnemyToolbar",0,-1,240,12,nil) glEnemyToolbar.colors = {0,1,2} glEnemyToolbar.border = { colors = {2,2,2}, width = 1, } glEnemyToolbar.onPress=function() if GameHelper.controlScheme==2 then GUIHelper.controlHoveredOver=nil end end glEnemyToolbarMana=GUIHelper:CreateGUIFrame("glEnemyToolbarMana",glEnemyToolbar.x+1,glEnemyToolbar.y+1,79,glEnemyToolbar.h-2,nil) glEnemyToolbarMana:addParent(glEnemyToolbar) glEnemyToolbarMana.controlName="MANA COUNTER" glEnemyToolbarMana.tooltipTexts=glTooltipsStrings.panelManaCount glEnemyToolbarMana.onHover=function(ref) if ref:visible() then GUIHelper.controlHoveredOver=ref GameHelper.cardGUIElemHoveredOver=nil end end glEnemyToolbarMana.colors = {13,15,8} glEnemyToolbarMana.border = { colors = {0,13,8}, width = 1, } glEnemyToolbarMana:Content(function(ref,x,y) local cardObj=GameHelper.enemyLeaderCard if cardObj==nil then return end local visCur=cardObj.stats.manaVisualCount.cur local visMax=cardObj.stats.manaVisualCount.max glEnemyToolbarMana.controlName="MANA COUNTER "..visCur.."/"..visMax rect(x,y,77,8,13) print("MANA",x+1,y+1,8) rect(x+ref.w-9,y,x+ref.w,8,13) print(visCur,x+ref.w-8,y+1,2) for i=0,visMax-1 do spr(i2 and 1 or 0),21+n*44+((i<2 or i>3) and (n==0 and -9 or 6) or (n==0 and -2 or -1)),39,25) card.name=(n==1 and "PlayerBattlefieldCard" or "EnemyBattlefieldCard") card.isPlayerCard=(n==1) card.isHandCard=false card.isLeaderCard=false card.pos=i+1 card.origX=card.x card.origY=card.y card.delayBeforeVisible=0 card:style(glGUIFrameStyleUnusableCard) card:Content(GUIHelper.BattlefieldCardDrawingFunction) card.onHover=function() if GameHelper.controlScheme<2 then GUIHelper.controlHoveredOver=card GameHelper.cardGUIElemHoveredOver=card end end card.onCleanRelease=function(ref) GUIHelper.controlClicked=card GameHelper.cardGUIElemSelected=card end card.onRelease=function(ref) if GameHelper.controlScheme==2 then GUIHelper.controlHoveredOver=nil GameHelper.cardGUIElemHoveredOver=nil end end card.onPress=function() if GameHelper.controlScheme==2 then GUIHelper.controlHoveredOver=card GameHelper.cardGUIElemHoveredOver=card else GUIHelper.controlClickHolding=card GameHelper.cardGUIElemClickHolding=card end end if n==0 then table.insert(GUIHelper.enemyBattlefieldCards,card) else table.insert(GUIHelper.playerBattlefieldCards,card) end end end local enemyLCardGUI = GUIHelper:CreateGUIFrame("glEnemyLeaderCardGUI",glEnemyToolbar:getCenterX()-40,glEnemyToolbar.y+1,80,18) enemyLCardGUI.name="EnemyLeaderCard" enemyLCardGUI.isHandCard=false enemyLCardGUI.isPlayerCard=false enemyLCardGUI.isLeaderCard=true enemyLCardGUI.origX=enemyLCardGUI.x enemyLCardGUI.origY=enemyLCardGUI.y enemyLCardGUI:style(glGUIFrameStyleActiveOKCard) enemyLCardGUI.onHover=function() if GameHelper.controlScheme<2 then GUIHelper.controlHoveredOver=enemyLCardGUI GameHelper.cardGUIElemHoveredOver=enemyLCardGUI end end enemyLCardGUI.onCleanRelease=function(ref) GUIHelper.controlClicked=enemyLCardGUI GameHelper.cardGUIElemSelected=enemyLCardGUI end enemyLCardGUI.onRelease=function(ref) if GameHelper.controlScheme==2 then GUIHelper.controlHoveredOver=nil GameHelper.cardGUIElemHoveredOver=nil end end enemyLCardGUI.onPress=function() if GameHelper.controlScheme==2 then GUIHelper.controlHoveredOver=enemyLCardGUI GameHelper.cardGUIElemHoveredOver=enemyLCardGUI else GUIHelper.controlClickHolding=enemyLCardGUI GameHelper.cardGUIElemClickHolding=enemyLCardGUI end end enemyLCardGUI:Content(GUIHelper.LeaderCardDrawingFunction) enemyLCardGUI.gameObj=GameHelper.enemyLeaderCard glEnemyLeaderCardGUI=enemyLCardGUI GUIHelper.enemyLeaderCard=enemyLCardGUI glPlayerToolbar= GUIHelper:CreateGUIFrame("glPlayerToolbar",0,97,240,12) glPlayerToolbar.colors = {0,0,0} glPlayerToolbar.border = { colors = {2,2,2}, width = 1, } glPlayerToolbar.getCenterX=function(ref) return ref.x+ref.w/2 end glPlayerToolbar.getCenterY=function(ref) return ref.y+ref.h/2 end glPlayerToolbarMana=GUIHelper:CreateGUIFrame("glPlayerToolbarMana",glPlayerToolbar.x+1,glPlayerToolbar.y+1,79,glPlayerToolbar.h-2,nil) glPlayerToolbarMana:addParent(glEnemyToolbar) glPlayerToolbarMana.controlName="MANA COUNTER" glPlayerToolbarMana.tooltipTexts=glTooltipsStrings.panelManaCount glPlayerToolbarMana.onHover=function(ref) if ref:visible() then GUIHelper.controlHoveredOver=ref GameHelper.cardGUIElemHoveredOver=nil end end glPlayerToolbarMana.colors = {13,15,8} glPlayerToolbarMana.border = { colors = {0,13,8}, width = 1, } glPlayerToolbarMana:Content(function(ref,x,y) local cardObj=GameHelper.playerLeaderCard if cardObj==nil then return end local visCur=cardObj.stats.manaVisualCount.cur local visMax=cardObj.stats.manaVisualCount.max glPlayerToolbarMana.controlName="MANA COUNTER "..visCur.."/"..visMax rect(x,y,77,8,13) print("MANA",x+1,y+1,8) rect(x+ref.w-9,y,x+ref.w,8,13) print(visCur,x+ref.w-8,y+1,2) for i=0,visMax-1 do spr(i10 and (screen.w-6)/2+1 or 0),screen.y+9+(i>10 and -99 or 0)+i*9,(screen.w-6)/2,9,glBackgroundWithBorderClickableGUIStyle,parentControl,tag.name) tagButton:addParent(screen) tagButton.unlocked=true tagButton.tagObj=tag local tagFunc=function(ref,x,y) local tag=ref.tagObj GUIHelper.ChoiceContentFunction(ref,x,y) if tag then if ref.unlocked then spr(tag.spr,x,y-1) end end end tagButton:Content(tagFunc) tagButton.clicked=false tagButton.onCleanRelease=function(ref) foreach(glSelectLeaderTagToAddGUI.tagsGUI,function(tag) tag.clicked=false tag.border=glBackgroundWithBorderClickableGUIStyle.border end) ref.clicked=not ref.clicked GUIHelper.InteractableActiveControlBaseClickFunc(ref) if ref.clicked then ref.border=glGUIFrameStyleActiveOKCard.border else ref.border=glBackgroundWithBorderClickableGUIStyle.border end glSelectLeaderTagToAddGUI.tagsSelected=ref end local tagFunc=function(ref) local tag=ref.tagObj if tag and ref.unlocked then table.insert(glGUIFrameMouseTooltip.textArray,{prefixSpr=tag.spr,text=tag:genNameAsStr(),color=14,smallFont=false}) local desc=tag:genDesc() --hack because of bug introduced with genDesc?? for n=0,(#desc) do local d=desc[n] if d then table.insert(glGUIFrameMouseTooltip.textArray,{text=d.str,color=d.c,smallFont=true}) end end UpdateMouse() end end tagButton.onHover=function(ref) if GameHelper.controlScheme<2 then tagFunc(ref) end end tagButton.onPress=function(ref) if GameHelper.controlScheme==2 then tagFunc(ref) end end table.insert(screen.tagsGUI,tagButton) end glSelectLeaderTagToAddGUIConfirm=GUIHelper:CreateButtonWidget("glSelectLeaderTagToAddGUIConfirm",screen:getCenterX()-20,screen.y+screen.h-11,40,9,glBackgroundWithBorderClickableGUIStyle,screen,"OK") glSelectLeaderTagToAddGUIConfirm.onCleanRelease=function(ref) local chosenTag=glSelectLeaderTagToAddGUI.tagsSelected if chosenTag then GameHelper.playerLeaderFormula:InsertTag(deepcopy(chosenTag.tagObj)) foreach(glSelectLeaderTagToAddGUI.tagsGUI,function(cardGUI) cardGUI.clicked=false cardGUI.border=glBackgroundWithBorderClickableGUIStyle.border cardGUI.tagObj=nil end) GameHelper.finishedChoosingArtifact=true GUIHelper.InteractableActiveControlBaseClickFunc(ref) glSelectLeaderTagToAddGUI:hide() end end glSelectLeaderTagToAddGUI=screen end function GUICreator:RemoveSelectLeaderTagScreen() if glSelectLeaderTagToAddGUI then Logger:Debug("removing SELECT TAG control",glMsgType.GUI) glSelectLeaderTagToAddGUI:remove() glSelectLeaderTagToAddGUI=nil else Logger:Debug("SELECT TAG control is already deleted!",glMsgType.GUI) end end function GUICreator:CreateRedrawingStartingCardsScreen() if glChooseStaringCardsGUI then Logger:Debug("REDRAW CARDS screen already exists!",glMsgType.GUI) return end Logger:Debug("Creating REDRAW CARDS screen",glMsgType.GUI) local screen=GUIHelper:CreateGUIFrame("glChooseStaringCardsGUI",2,glScreenPixelHeight/2-47,glScreenPixelWidth-3,96,glBackgroundWithBorderGUIBlackStyle) screen:Content(function(ref,x,y) print("CHOOSE WHICH CARDS TO REDRAW:",x+1,y+1,5) end) local confirmS=GUIHelper:CreateButtonWidget("glConfirmStartingCardsGUI",screen:getCenterX()-20,screen.y+screen.h-11,40,9,glBackgroundWithBorderClickableGUIStyle,screen,"OK") confirmS.onCleanRelease=function(ref) GameHelper.finishedChoosingCards=true glEndTurnButton:makeVisible() GUIHelper.InteractableActiveControlBaseClickFunc(ref) end glRerollStartingCardsGUI=GUIHelper:CreateButtonWidget("glRerollStartingCardsGUI",screen:getRightX()-52,screen.y+screen.h-11,50,9,glBackgroundWithBorderClickableGUIStyle,screen,"REROLL") glRerollStartingCardsGUI.onCleanRelease=function(ref) GameHelper.RerollStartingCards=true end glConfirmStartingCardsGUI=confirmS glChooseStaringCardsGUI=screen end function GUICreator:RemoveRedrawingStartingCardsScreen() if glChooseStaringCardsGUI then Logger:Debug("removing REDRAW CARDS screen",glMsgType.GUI) glChooseStaringCardsGUI:remove() glChooseStaringCardsGUI=nil else Logger:Debug("REDRAW CARDS screen is already deleted!",glMsgType.GUI) end end function GUICreator:CreateInventoryScreen() if gllnventoryScreenFrameGUI then Logger:Debug("INVENTORY screen already exists!",glMsgType.GUI) return end Logger:Debug("Creating INVENTORY screen",glMsgType.GUI) local hoverFunc= function(ref) if GameHelper.controlScheme<2 then GUIHelper.controlHoveredOver=ref GameHelper.cardGUIElemHoveredOver=ref end end local screen=GUIHelper:CreateGUIFrame("gllnventoryScreenFrameGUI",0,0,glScreenPixelWidth,glScreenPixelHeight,glBackgroundWithBorderGUIBlackStyle) screen:Content(function(ref,x,y) print("YOUR INVENTORY",x+1,y+1,5) end) glStartGameModeFrameOKGUI=GUIHelper:CreateButtonWidget("glStartGameModeFrameOKGUI",screen:getCenterX()-20,screen.y+screen.h-11,40,9,glBackgroundWithBorderClickableGUIStyle,frame,"OK") glStartGameModeFrameOKGUI:addParent(screen) glStartGameModeFrameOKGUI.onCleanRelease=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref) gllnventoryScreenFrameGUI:hide() glRunProgressFrameGUI:show() end local scrollDrawCardsInDeckFunc=function(down) local d={} foreach(GameHelper.allDeckTemplates[GameHelper.playerChoosenDeckID],function(cardID) table.insert(d,GameHelper.allCards[cardID]) end) glStartGameModeFrameDeckGUI.scrollAmount=down and (math.max(math.min(glStartGameModeFrameDeckGUI.scrollAmount+4,#d-10),0)) or (math.max(0,glStartGameModeFrameDeckGUI.scrollAmount-4)) table.sort(d,function(a,b) return a.stats.manaCost.cur0 and "CONFIRM" or "CANCEL") end end local cardsGUI={} for i=0,9 do local cardGUI=GUIHelper:CreateGUIFrame("glStartGameModeFrameDeckGUI_card_"..i,glStartGameModeFrameDeckGUI.x+2,glStartGameModeFrameDeckGUI.y+9+i*9,glStartGameModeFrameDeckGUI.w-16,10,glGUIFrameStyleUnusableCard) cardGUI.isCard=true cardGUI:addParent(glStartGameModeFrameDeckGUI) cardGUI.cardObj=GameHelper.allCards["A000"] cardGUI:Content(GUIHelper.ListCardDrawingFunction) cardGUI.onHover=hoverFunc cardGUI.onPress=pressFunc cardGUI.onRelease=deckCardReleaseFunc cardGUI.toDelete=false table.insert(cardsGUI,cardGUI) end glStartGameModeFrameDeckGUI.playerDeckCardsGUI=cardsGUI glStartGameModeFrameDeckGUI.scrollAmount=0 local unlocked=AchievementsHelper.RemoveCardsUnlocked glStartGameModeDeckRemoveCardsButtonGUI=GUIHelper:CreateButtonWidget("glStartGameModeDeckRemoveCardsButtonGUI",glStartGameModeFrameDeckGUI:getCenterX()-38, glStartGameModeFrameDeckGUI.y+glStartGameModeFrameDeckGUI.h-11,73,9,glBackgroundWithBorderClickableGUIStyle,glStartGameModeFrameDeckGUI,unlocked and "REMOVE CARDS" or "WIN 2 TIMES",false,unlocked and 15 or 3) glStartGameModeDeckRemoveCardsButtonGUI.onCleanRelease=function(ref) local unlocked=AchievementsHelper.RemoveCardsUnlocked if not unlocked then return end local removeMode=not glStartGameModeFrameDeckGUI.removeMode if not removeMode then glStartGameModeFrameDeckGUI.selectedCards={} end if ref.text=="CONFIRM" then local deck=GameHelper.allDeckTemplates[GameHelper.playerChoosenDeckID] for i=(#glStartGameModeFrameDeckGUI.playerDeckCardsGUI),1,-1 do local card=glStartGameModeFrameDeckGUI.playerDeckCardsGUI[i] if card and card.toDelete then for j=(#deck),1,-1 do local cardID=card.cardObj.id local deckCID=deck[j] if deckCID==cardID then table.remove(deck,j) break end end end end GameHelper.allDeckTemplates[GameHelper.playerChoosenDeckID]=deck local d=GameHelper:InitDeckAndHandFromID(GameHelper.playerChoosenDeckID,true) scrollDrawCardsInDeckFunc(true) end ref.text=removeMode and ((#glStartGameModeFrameDeckGUI.selectedCards)>0 and "CONFIRM" or "CANCEL") or "REMOVE CARDS" foreach(glStartGameModeFrameDeckGUI.playerDeckCardsGUI,function(playerDeckCardGUI) playerDeckCardGUI.border=removeMode and glGUIFrameStyleActiveOKCard.border or glGUIFrameStyleUnusableCard.border playerDeckCardGUI.toDelete=false end) glStartGameModeFrameDeckGUI.removeMode=removeMode GUIHelper.InteractableActiveControlBaseClickFunc(ref) end local downButtonGUI=GUIHelper:CreateButtonWidget("glStartGameModeFrameDeckGUI_downButton",glStartGameModeFrameDeckGUI.x+glStartGameModeFrameDeckGUI.w-13,glStartGameModeFrameDeckGUI.y+glStartGameModeFrameDeckGUI.h-30,11,9,glBackgroundWithBorderClickableGUIStyle,screen,"\\/",true) downButtonGUI:addParent(glStartGameModeFrameDeckGUI) downButtonGUI.onCleanRelease=function(ref) scrollDrawCardsInDeckFunc(true) GUIHelper.InteractableActiveControlBaseClickFunc(ref) end local upButtonGUI=GUIHelper:CreateButtonWidget("glStartGameModeFrameDeckGUI_downButton",glStartGameModeFrameDeckGUI.x+glStartGameModeFrameDeckGUI.w-13,glStartGameModeFrameDeckGUI.y+20,11,9,glBackgroundWithBorderClickableGUIStyle,screen,"/\\",true) upButtonGUI:addParent(glStartGameModeFrameDeckGUI) upButtonGUI.onCleanRelease=function(ref) scrollDrawCardsInDeckFunc(false) GUIHelper.InteractableActiveControlBaseClickFunc(ref) end glStartGameModeFrameArtifactsGUI=GUIHelper:CreateGUIFrame("glStartGameModeFrameArtifactsGUI",screen.x+2,screen.y+12,screen.w/3+2,screen.h-24,glBackgroundWithBorderGUIBlackStyle) glStartGameModeFrameArtifactsGUI:addParent(screen) glStartGameModeFrameDeckGUI.artifactGUIs={} glStartGameModeFrameArtifactsGUI:Content(function(ref,x,y) print("Artifacts:("..#GameHelper.playerLeaderCard.artifactsIDList.."/"..RuleHelper.maxArtifactsPerRun..")",x+1,y+1,5) i=0 foreach(GameHelper.playerLeaderCard.artifactsIDList,function(artifactID) i=i+1 end) end) local cardsGUI={} local artiOnHover=function(ref) if GameHelper.controlScheme<2 then local tag=ref.artifactObj glGUIFrameMouseTooltip.textArray={} if tag then table.insert(glGUIFrameMouseTooltip.textArray,{text=tag.name,color=14,smallFont=false}) foreach(tag.desc,function(d) table.insert(glGUIFrameMouseTooltip.textArray,{text=d.str,color=d.c,smallFont=true}) end) UpdateMouse() end end end local artiOnPress=function(ref) if GameHelper.controlScheme==2 then local tag=ref.artifactObj glGUIFrameMouseTooltip.textArray={} if tag then table.insert(glGUIFrameMouseTooltip.textArray,{text=tag.name,color=14,smallFont=false}) foreach(tag.desc,function(d) table.insert(glGUIFrameMouseTooltip.textArray,{text=d.str,color=d.c,smallFont=true}) end) UpdateMouse() end end end for i=0,5 do local cardGUI=GUIHelper:CreateGUIFrame("glStartGameModeFrameDeckGUI_card_"..i,glStartGameModeFrameArtifactsGUI.x+2,glStartGameModeFrameArtifactsGUI.y+9+i*17,glStartGameModeFrameArtifactsGUI.w-4,17,glGUIFrameStyleUnusableCard) cardGUI.isCard=true cardGUI:addParent(glStartGameModeFrameDeckGUI) cardGUI.artifactObj=nil cardGUI:Content(function(ref,x,y) if ref.artifactObj then local s=ref.artifactObj.name if (#s)>18 then local split=string.split(s," ") local l="" local i=0 foreach(split,function(word) if #(l..word)>12 then print(l,x+1,y+1+8*i,9) l=word i=i+1 else l=l..((#l)>0 and " " or "")..word end end) if (#l)>0 then print(l,x+1,y+1+8*i,9) end else print(s,x+1,y+5,9,false,1,(#s)>13) end end end) cardGUI.onHover=artiOnHover cardGUI.onPress=artiOnPress table.insert(glStartGameModeFrameDeckGUI.artifactGUIs,cardGUI) end gllnventoryScreenFrameGUI=screen end function GUICreator:RemoveInventoryScreen() if gllnventoryScreenFrameGUI then Logger:Debug("removing INVENTORY screen",glMsgType.GUI) gllnventoryScreenFrameGUI:remove() gllnventoryScreenFrameGUI=nil else Logger:Debug("INVENTORY screen is already deleted!",glMsgType.GUI) end end function GUICreator:CreateChooseLegendaryCardScreen() if glChooseLegendaryTreasureGUI then Logger:Debug("CHOOSE LEGENDARY SCREEN screen already exists!",glMsgType.GUI) return end Logger:Debug("Creating LEGENDARY SCREEN screen",glMsgType.GUI) local screen = GUIHelper:CreateGUIFrame("glChooseLegendaryTreasureGUI",0,0,glScreenPixelWidth,glScreenPixelHeight,glBackgroundWithBorderGUIBlackStyle) screen:Content(function(ref,x,y) print("Choose one card to add to your deck: ",x+1,y+1,5) end) local hoverFunc= function(ref) if GameHelper.controlScheme<2 then GUIHelper.controlHoveredOver=ref GameHelper.cardGUIElemHoveredOver=ref end end screen.cards={} for i=0,2 do local card=GUIHelper:CreateGUIFrame("glChooseLegendaryTreasureGUI_cards_"..i,screen.x+2+40+i*33+i*20,screen.y+(screen.h-20)/2-35,41,73) card.name="FindTAGCard" card.pos=i+1 card.drawX=false card.origX=card.x card.origY=card.y card:addParent(screen) card:style(glGUIFrameStyleUnusableCard) card.onHover=hoverFunc card.onCleanRelease=function(ref) glChooseLegendaryTreasureGUI.chosenCard=ref foreach(glChooseLegendaryTreasureGUI.cards,function(cardGUI) cardGUI.drawX=true end) ref.drawX=false SfxHelper:PlaySFX(glSFXConfirmGUIData.id,glSFXConfirmGUIData.noteDef) end card.onPress=function(ref) ref:onHover() if GameHelper.controlScheme==2 then GUIHelper.controlHoveredOver=ref end end card:Content(GUIHelper.HandCardDrawingFunction) table.insert(screen.cards,card) end glChooseLegendaryTreasureConfirmGUI=GUIHelper:CreateButtonWidget("glChooseLegendaryTreasureConfirmGUI",screen:getCenterX()-20,screen.y+screen.h-11,40,9,glBackgroundWithBorderClickableGUIStyle,screen,"OK") glChooseLegendaryTreasureConfirmGUI.onCleanRelease=function(ref) if glChooseLegendaryTreasureGUI.chosenCard then local deck=deepcopy(GameHelper.allDeckTemplates[GameHelper.playerChoosenDeckID]) table.insert(deck, glChooseLegendaryTreasureGUI.chosenCard.cardObj.id) GameHelper.allDeckTemplates["PLAYER_DECK"]=deck glChooseLegendaryTreasureGUI.chosenCard=nil foreach(glChooseLegendaryTreasureGUI.cards,function(cardGUI) cardGUI.drawX=false cardGUI.cardObj=nil end) GameHelper.finishedChoosingArtifact=true GUIHelper.InteractableActiveControlBaseClickFunc(ref) glChooseLegendaryTreasureGUI:hide() GUICreator:RemoveChooseLegendaryCardScreen() end end screen:hide() glChooseLegendaryTreasureGUI=screen end function GUICreator:RemoveChooseLegendaryCardScreen() if glChooseLegendaryTreasureGUI then Logger:Debug("removing CHOOSE LEGEN. SCREEN screen",glMsgType.GUI) glChooseLegendaryTreasureGUI:remove() glChooseLegendaryTreasureGUI=nil else Logger:Debug("CHOOSE LEGEN. SCREEN screen is already deleted!",glMsgType.GUI) end end function GUICreator:CreateGameEndScreen() if glGUIFrameEndScreenBackground then Logger:Debug("GAME END screen already exists!",glMsgType.GUI) return end Logger:Debug("Creating GAME END screen",glMsgType.GUI) local screen = GUIHelper:CreateGUIFrame("glGUIFrameEndScreenBackground",0,0,glScreenPixelWidth,glScreenPixelHeight,glBackgroundWithBorderGUIBlackStyle) screen:Content(function(ref,x,y) print("RUN SUMMARY ",x+1,y+1,5) end) glGUIFrameEndScreenGeneralScoreSummary = GUIHelper:CreateTextLogWithTitleInFoldableFrame("glGUIFrameEndScreenGeneralScoreSummary",screen.x+2,screen.y+9,screen.w-4,32,"BASIC SCORE:",true) glGUIFrameEndScreenGeneralScoreSummary:addParent(screen) glGUIFrameEndScreenUnitsScoreSummary = GUIHelper:CreateTextLogWithTitleInFoldableFrame("glGUIFrameEndScreenUnitsScoreSummary",glGUIFrameEndScreenGeneralScoreSummary.x,glGUIFrameEndScreenGeneralScoreSummary.y+11,glGUIFrameEndScreenGeneralScoreSummary.w,53,"UNIT SCORE:",true) glGUIFrameEndScreenUnitsScoreSummary:addParent(screen) glGUIFrameEndScreenTotalScoreSummary = GUIHelper:CreateTextLogWithTitleInFoldableFrame("glGUIFrameEndScreenTotalScoreSummary",glGUIFrameEndScreenUnitsScoreSummary.x,glGUIFrameEndScreenUnitsScoreSummary.y+11,glGUIFrameEndScreenUnitsScoreSummary.w,32,"TOTAL SCORE:",true) glGUIFrameEndScreenTotalScoreSummary:addParent(screen) glGUIFrameEndScreenUnlocksSummary = GUIHelper:CreateTextLogWithTitleInFoldableFrame("glGUIFrameEndScreenUnlocksSummary",glGUIFrameEndScreenUnitsScoreSummary.x,glGUIFrameEndScreenTotalScoreSummary.y+11,glGUIFrameEndScreenUnitsScoreSummary.w,32,"UNLOCKS:",true) glGUIFrameEndScreenUnlocksSummary:addParent(screen) glGUIFrameEndScreenUnlocksSummary:ClickFoldButton() glGUIFrameEndScreenTotalScoreSummary:ClickFoldButton() glGUIFrameEndScreenUnitsScoreSummary:ClickFoldButton() glGUIFrameEndScreenGeneralScoreSummary:ClickFoldButton() glGUIFrameEndScreenGeneralScoreSummary:RegisterControlToMoveOnFoldAction(glGUIFrameEndScreenUnitsScoreSummary) glGUIFrameEndScreenUnitsScoreSummary:RegisterControlToMoveOnFoldAction(glGUIFrameEndScreenTotalScoreSummary) glGUIFrameEndScreenTotalScoreSummary:RegisterControlToMoveOnFoldAction(glGUIFrameEndScreenUnlocksSummary) glGUIFrameEndScreenUnlocksSummary:ClickFoldButton() glGUIFrameEndScreenTotalScoreSummary:ClickFoldButton() glGUIFrameEndScreenButtonRestart= GUIHelper:CreateButtonWidget("glGUIFrameEndScreenButtonRestart",screen.x+screen.w/2-48,screen.y+screen.h-11,97,9,glBackgroundWithBorderClickableGUIStyle,screen,"BACK TO MAIN MENU") glGUIFrameEndScreenButtonRestart.onCleanRelease=function(ref) GameHelper.lastNumOfPlayingGameMode=GameHelper.numOfPlayingGameMode GUIHelper.InteractableActiveControlBaseClickFunc(ref) reset() end glGUIFrameEndScreenBackground=screen end function GUICreator:RemoveGameEndScreen() if glGUIFrameEndScreenBackground then Logger:Debug("removing GAME END screen",glMsgType.GUI) glGUIFrameEndScreenBackground:remove() glGUIFrameEndScreenBackground=nil else Logger:Debug("GAME END screen is already deleted!",glMsgType.GUI) end end function GUICreator:CreateAddEnemyToDeckScreen() if glAddLeaderCardToDeckGUI then Logger:Debug("ADD ENEMY TO DECK screen already exists!",glMsgType.GUI) return end Logger:Debug("Creating ENEMY TO DECK screen",glMsgType.GUI) local screen=GUIHelper:CreateGUIFrame("glAddLeaderCardToDeckGUI",0,0,glScreenPixelWidth,glScreenPixelHeight,glBackgroundWithBorderGUIBlackStyle) screen:Content(function(ref,x,y) print("LOOTING ENEMY: ",x+1,y+1,5) print("You can add weaker version of your last enemy \nto your deck if you wish.",x+4,y+10,15,false,1,1,true) end) local hoverFunc= function(ref) if GameHelper.controlScheme<2 then GUIHelper.controlHoveredOver=ref GameHelper.cardGUIElemHoveredOver=ref end end local card=GUIHelper:CreateGUIFrame("glAddLeaderCardToDeckGUI_card",screen:getCenterX()-21,screen.y+(screen.h-20)/2-25,41,73) card.name="FindTAGCard" card.pos=i+1 card.drawX=false card.cardObj=GameHelper.allCards[GameHelper.enemyLeaderCardToOfferForPlayer] card.origX=card.x card.origY=card.y card:addParent(screen) card:style(glGUIFrameStyleUnusableCard) card.onHover=hoverFunc card.onPress=function(ref) ref:onHover() if GameHelper.controlScheme==2 then GUIHelper.controlHoveredOver=ref end end card:Content(GUIHelper.HandCardDrawingFunction) screen.card=card local okClickFunc=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref) if glAddLeaderCardToDeckGUI.card.cardObj then local deck=deepcopy(GameHelper.allDeckTemplates[GameHelper.playerChoosenDeckID]) table.insert(deck, glAddLeaderCardToDeckGUI.card.cardObj.id) GameHelper.allDeckTemplates[GameHelper.playerChoosenDeckID]=deck local d=GameHelper:InitDeckAndHandFromID(GameHelper.playerChoosenDeckID,true) end glAddLeaderCardToDeckGUI.cardObj=nil GameHelper.enemyLeaderCardToOfferForPlayer=nil glAddLeaderCardToDeckGUI:hide() end local skipClickFunc=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref) GameHelper.enemyLeaderCardToOfferForPlayer=nil glAddLeaderCardToDeckGUI:hide() end local okButton=GUIHelper:CreateButtonWidget("glAddLeaderCardToDeckGUI_okButton",screen:getCenterX()-20,screen.y+glScreenPixelHeight-11,40,9,glBackgroundWithBorderClickableGUIStyle,screen,"OK") okButton:addParent(screen) okButton.onCleanRelease=okClickFunc local skipButton=GUIHelper:CreateButtonWidget("glAddLeaderCardToDeckGUI_skipButton",screen:getCenterX()+30,screen.y+glScreenPixelHeight-11,40,9,glBackgroundWithBorderClickableGUIStyle,screen,"SKIP") skipButton:addParent(screen) skipButton.onCleanRelease=skipClickFunc glAddLeaderCardToDeckGUI=screen end function GUICreator:RemoveAddEnemyToDeckScreen() if glAddLeaderCarEdToDeckGUI then Logger:Debug("removing ADD ENEMY TO DECK screen",glMsgType.GUI) glAddLeaderCardToDeckGUI:remove() glAddLeaderCardToDeckGUI=nil else Logger:Debug("ADD ENEMY TO DECK screen is already deleted!",glMsgType.GUI) end end function GUICreator:CreateChooseBucketsScreen() if glChooseBucketsGUI then Logger:Debug("CHOOSE BUCKETS screen already exists!",glMsgType.GUI) return end Logger:Debug("Creating CHOOSE BUCKETS screen",glMsgType.GUI) --screen var is below local frameContentFunc=function(ref,x,y) print("ADD 3 CARDS TO YOUR DECK: ",x+1,y+1,5) end local okClickFunc=function(ref) if glChooseBucketsGUI.choosenCards then GUIHelper.InteractableActiveControlBaseClickFunc(ref) GameHelper.choosenCardsFromBucket=glChooseBucketsGUI.choosenCards glChooseBucketsGUI.choosenCards=nil GameHelper.finishedChoosingCardBucket=true end glChooseBucketsGUI:resetGUIFunc() glChooseBucketsGUI:hide() end GameHelper.bucketOption1=glCardBuckets["ANIMAL"] GameHelper.bucketOption2=glCardBuckets["HUMAN"] GameHelper.bucketOption3=glCardBuckets["UNDEAD"] GameHelper.bucketOption1Var=1 GameHelper.bucketOption2Var=1 GameHelper.bucketOption3Var=1 local option1ContentFunc=function(ref,x,y) print(GameHelper.bucketOption1.name,x+1,y+1,ref.titleColor) end local option1ClickFunc= function(ref) ref:basicOptionClickFunc() glChooseBucketsGUI.choosenCards=GameHelper.bucketOption1.buckets[GameHelper.bucketOption1Var] end local option1TextStr="" local option2ContentFunc=function(ref,x,y) print(GameHelper.bucketOption2.name,x+1,y+1,ref.titleColor) end local option2ClickFunc= function(ref) ref:basicOptionClickFunc() glChooseBucketsGUI.choosenCards=GameHelper.bucketOption2.buckets[GameHelper.bucketOption2Var] end local option2TextStr="" local option3ContentFunc=function(ref,x,y) print(GameHelper.bucketOption3.name,x+1,y+1,ref.titleColor) end local option3ClickFunc= function(ref) ref:basicOptionClickFunc() glChooseBucketsGUI.choosenCards=GameHelper.bucketOption3.buckets[GameHelper.bucketOption3Var] end local option3TextStr="" local screen=GUIHelper:CreateGUIDialogWithXChoices("glChooseBucketsGUI",0,0,glScreenPixelWidth,glScreenPixelHeight,glBackgroundWithBorderGUIBlackStyle,frameContentFunc,okClickFunc,3,1, {{optionContentFunc=option1ContentFunc,optionClickFunc=option1ClickFunc,optionTextStr=option1TextStr}, {optionContentFunc=option2ContentFunc,optionClickFunc=option2ClickFunc,optionTextStr=option2TextStr}, {optionContentFunc=option3ContentFunc,optionClickFunc=option3ClickFunc,optionTextStr=option3TextStr}}) local skipClickFunc=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref) glChooseBucketsGUI.choosenCards=nil GameHelper.skipCardBuckets=true GameHelper.finishedChoosingCardBucket=true glChooseBucketsGUI:resetGUIFunc() glChooseBucketsGUI:hide() end local skipButton=GUIHelper:CreateButtonWidget("glChooseBucketsGUI_skipButton",screen:getCenterX()+30,screen.y+screen.h-11,40,9,glBackgroundWithBorderClickableGUIStyle,frame,"SKIP") skipButton:addParent(screen) skipButton.onCleanRelease=skipClickFunc local buckets={GameHelper.bucketOption1,GameHelper.bucketOption2,GameHelper.bucketOption3} local bucketCardFunc=GUIHelper.BucketCardDrawingFunction local hoverFunc= function(ref) if GameHelper.controlScheme<2 then GUIHelper.controlHoveredOver=ref GameHelper.cardGUIElemHoveredOver=ref end end local pressFunc= function(ref) if GameHelper.controlScheme==2 then GUIHelper.controlHoveredOver=ref GameHelper.cardGUIElemHoveredOver=ref end end local releaseFunc=function(ref) if GameHelper.controlScheme==2 then GUIHelper.controlHoveredOver=nil GameHelper.cardGUIElemHoveredOver=nil end glChooseBucketsGUI.choosenCards=(ref.index==1 and GameHelper.bucketOption1.buckets[GameHelper.bucketOption1Var] or (ref.index==2 and GameHelper.bucketOption2.buckets[GameHelper.bucketOption2Var] or GameHelper.bucketOption3.buckets[GameHelper.bucketOption3Var])) if ref.parent.basicOptionClickFunc then ref.parent:basicOptionClickFunc() end end for i=1,3 do local cardsGUI={} local card1GUI=GUIHelper:CreateGUIFrame("glChooseBucketsGUI_"..i.."_1",screen.optionsGUI[i].x+9,screen.optionsGUI[i].y+8,screen.optionsGUI[i].w-21,26,glGUIFrameStyleUnusableCard) card1GUI.isCard=true card1GUI.index=i card1GUI:addParent(screen.optionsGUI[i]) card1GUI.cardObj=GameHelper.allCards[buckets[i].buckets[GameHelper.bucketOption1Var][1]] card1GUI:Content(bucketCardFunc) card1GUI.onHover=hoverFunc card1GUI.onPress=pressFunc card1GUI.onRelease=releaseFunc card1GUI.onCleanRelease=releaseFunc card1GUI.basicOptionClickFunc=GUIHelper.basicOptionClickFunc table.insert(cardsGUI,card1GUI) local card2GUI=GUIHelper:CreateGUIFrame("glChooseBucketsGUI_"..i.."_2",card1GUI.x,card1GUI.y+card1GUI.h+1,card1GUI.w,card1GUI.h,glGUIFrameStyleUnusableCard) card2GUI.isCard=true card2GUI.index=i card2GUI:addParent(screen.optionsGUI[i]) card2GUI.cardObj=GameHelper.allCards[buckets[i].buckets[GameHelper.bucketOption2Var][2]] card2GUI:Content(bucketCardFunc) card2GUI.onHover=hoverFunc card2GUI.onPress=pressFunc card2GUI.onRelease=releaseFunc card2GUI.onCleanRelease=releaseFunc card2GUI.basicOptionClickFunc=GUIHelper.basicOptionClickFunc table.insert(cardsGUI,card2GUI) local card3GUI=GUIHelper:CreateGUIFrame("glChooseBucketsGUI_"..i.."_3",card2GUI.x,card2GUI.y+card2GUI.h+1,card2GUI.w,card2GUI.h,glGUIFrameStyleUnusableCard) card3GUI.isCard=true card3GUI.index=i card3GUI:addParent(screen.optionsGUI[i]) card3GUI.cardObj=GameHelper.allCards[buckets[i].buckets[GameHelper.bucketOption3Var][3]] card3GUI:Content(bucketCardFunc) card3GUI.onHover=hoverFunc card3GUI.onPress=pressFunc card3GUI.onRelease=releaseFunc card3GUI.onCleanRelease=releaseFunc card3GUI.basicOptionClickFunc=GUIHelper.basicOptionClickFunc table.insert(cardsGUI,card3GUI) screen.optionsGUI[i].cardsGUI=cardsGUI end glChooseBucketsGUI=screen end function GUICreator:RemoveChooseBucketsScreen() if glChooseBucketsGUI then Logger:Debug("removing CHOOSE BUCKETS screen",glMsgType.GUI) glChooseBucketsGUI:remove() glChooseBucketsGUI=nil else Logger:Debug("CHOOSE BUCKETS screen is already deleted!",glMsgType.GUI) end end function GUICreator:RemoveRunProgressScreen() if glRunProgressFrameGUI then Logger:Debug("removing RUN PROGRESS screen",glMsgType.GUI) glRunProgressFrameGUI:remove() glRunProgressFrameGUI=nil else Logger:Debug("RUN PROGRESS screen is already deleted!",glMsgType.GUI) end end function GUICreator:CreateChooseDeckScreen() if glChooseStaringDeckGUI then Logger:Debug("CHOOSE DECK screen already exists!",glMsgType.GUI) return end Logger:Debug("Creating CHOOSE DECK screen",glMsgType.GUI) --choose deck gui local frameContentFunc=function(ref,x,y) print("CHOOSE STARTING DECK ",x+1,y+1,5) end local okClickFunc=function(ref) if GameHelper.playerChoosenDeckID then GUIHelper.InteractableActiveControlBaseClickFunc(ref) GameHelper.finishedChoosingDeck=true Logger:Trace("copy of the player deck:"..GameHelper.playerChoosenDeckID,glMsgType.INIT_GAME) GameHelper.playerChoosenDeckOrigID=GameHelper.playerChoosenDeckID local deck=deepcopy(GameHelper.allDeckTemplates[GameHelper.playerChoosenDeckID]) GameHelper.allDeckTemplates["PLAYER_DECK"]=deck GameHelper.playerChoosenDeckID="PLAYER_DECK" Logger:Debug("PLAYER_DECK DECK:"..(deck and #(deck) or "NIL!"),glMsgType.INIT_GAME) GUICreator:CreateInventoryScreen() GUICreator:RemoveChooseDeckScreen() GUICreator:RemoveLeaderCreationScreen() end end local decks={"DECK003","DECK005","DECK004","DECK007","DECK006","DECK009","DECK008","DECK030","DECK029"} local data={} local i=0 foreach(decks,function(deckID) local optionContentFunc=function(ref,x,y) print(glCSVDecksDefinitionsByID[deckID].name,x+1,y+1,ref.titleColor) end local lockedContentFunc=function(ref,x,y) print("NOT UNLOCKED",x+1,y+1,1) end local optionClickFunc= function(ref) ref:basicOptionClickFunc() GameHelper.playerChoosenDeckID=deckID end local emptyFunc=function(ref) end Logger:Trace("deckID:"..deckID,glMsgType.INIT_GAME) local optionTextStr=glCSVDecksDefinitionsByID[deckID].desc if i>=1 and i<9 then if not AchievementsHelper.unlocksData["DECK"..i].unlocked then optionContentFunc=lockedContentFunc optionClickFunc=emptyFunc end end if i==1 then if not AchievementsHelper.unlocksData.DECK1.unlocked then optionTextStr="^03Play once to unlock" end elseif i==2 then if not AchievementsHelper.unlocksData.DECK2.unlocked then optionTextStr="^03Play twice to unlock" end elseif i==3 then if not AchievementsHelper.unlocksData.DECK3.unlocked then optionTextStr="^03Play thrice to unlock" end elseif i==4 then if not AchievementsHelper.unlocksData.DECK4.unlocked then optionTextStr="^03Play four times to unlock" end elseif i==5 then if not AchievementsHelper.unlocksData.DECK5.unlocked then optionTextStr="^03Play five times to unlock" end elseif i==6 then if not AchievementsHelper.unlocksData.DECK6.unlocked then optionTextStr="^03Win once to unlock" end elseif i==7 then if not AchievementsHelper.unlocksData.DECK7.unlocked then optionTextStr="^03Win twice to unlock" end elseif i==8 then if not AchievementsHelper.unlocksData.DECK8.unlocked then optionTextStr="^03Win thrice to unlock" end end table.insert(data,{optionContentFunc=optionContentFunc,optionClickFunc=optionClickFunc,optionTextStr=optionTextStr}) i=i+1 end) glChooseStaringDeckGUI=GUIHelper:CreateGUIDialogWithXChoices("glChooseStaringDeckGUI",0,0,glScreenPixelWidth,glScreenPixelHeight,glBackgroundWithBorderGUIBlackStyle,frameContentFunc,okClickFunc,9,3,data) glBackFromChooseStaringDeckGUI=GUIHelper:CreateButtonWidget("glBackFromChooseStaringDeckGUI",glChooseStaringDeckGUI:getCenterX()+30,glChooseStaringDeckGUI.y+glChooseStaringDeckGUI.h-11,40,9,glBackgroundWithBorderClickableGUIStyle,glChooseStaringDeckGUI,"BACK") glBackFromChooseStaringDeckGUI:addParent(glChooseStaringDeckGUI) glBackFromChooseStaringDeckGUI.onCleanRelease=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref) glCreateLeaderCardGUI:show() glCreateLeaderCardGUI:allToFront() end end function GUICreator:RemoveChooseDeckScreen() if glChooseStaringDeckGUI then Logger:Debug("removing CHOOSE DECK screen",glMsgType.GUI) glChooseStaringDeckGUI:remove() glChooseStaringDeckGUI=nil else Logger:Debug("CHOOSE DECK screen is already deleted!",glMsgType.GUI) end end function GUICreator:CreateLeaderCreationScreen() if glCreateLeaderCardGUI then Logger:Debug("LEADER CREATION screen already exists!",glMsgType.GUI) return end Logger:Debug("Creating LEADER CREATION screen",glMsgType.GUI) local screen=GUIHelper:CreateGUIFrame("glCreateLeaderCardGUI",0,0,glScreenPixelWidth,glScreenPixelHeight,glBackgroundWithBorderGUIBlackStyle) screen:Content(function(ref,x,y) print("CREATE YOUR LEADER UNIT",x+1,y+1,5) if AchievementsHelper.CreateLeaderSelectTagsUnlocked then print("("..GameHelper.playerLeaderCard.stats.pointsToAllocate.cur.." points left)",x+136,y+1,(GameHelper.playerLeaderCard.stats.pointsToAllocate.cur>0 and 14 or 5)) end end) if AchievementsHelper.CreateLeaderSelectTagsUnlocked then else GUICreator:CreateChooseDeckScreen() end glCreateLeaderCardStatsGUI=GUIHelper:CreateGUIFrame("glCreateLeaderCardStatsGUI",screen.x+2,screen.y+34,68,51,glBackgroundWithBorderGUIBlackStyle) glCreateLeaderCardStatsGUI:addParent(screen) glCreateLeaderCardStatsGUI:Content(function(ref,x,y) if AchievementsHelper.CreateLeaderTweakStatsUnlocked then print("TWEAK STATS:",x+1,y+1,11) print("("..GameHelper.playerLeaderCard.stats.pointsToAllocate.cur.." points left)",x+1,y+8,(GameHelper.playerLeaderCard.stats.pointsToAllocate.cur>0 and 14 or 11),false,1,true) else print("NOT UNLOCKED",x+1,y+1,10,false,1,true) print("Play once to \nunlock editing \nstats",x+1,y+8,10,false,1,true) end end) local tweaksStatsArr={{},{}} if AchievementsHelper.CreateLeaderTweakStatsUnlocked then local createLStatsATKGUI=GUIHelper:CreateGUIFrame("createLStatsATKGUI",glCreateLeaderCardStatsGUI.x+2,glCreateLeaderCardStatsGUI.y+17,20,32,glBackgroundWithBorderGUIBlackStyle) createLStatsATKGUI:addParent(glCreateLeaderCardStatsGUI) createLStatsATKGUI:Content(function(ref,x,y) y=y+ref.h/2-5 rect(x+0,y,ref.w,8,14) spr(256,x+ref.w-10,y,0) print(GameHelper.playerLeaderCard.stats.attack.cur,x+2,y+2,2) end) local attackUpButtonGUI=GUIHelper:CreateButtonWidget("attackUpButtonGUI",createLStatsATKGUI.x+2,createLStatsATKGUI.y+2,16,9,glBackgroundWithBorderClickableGUIStyle,screen,"/\\") attackUpButtonGUI:addParent(createLStatsATKGUI) attackUpButtonGUI.onCleanRelease=function(ref) if GameHelper.playerLeaderCard.stats.pointsToAllocate.cur>1 then GUIHelper.InteractableActiveControlBaseClickFunc(ref) local stat=GameHelper.playerLeaderCard.stats.attack stat.max=stat.max+RuleHelper.atkPerPoint*2 stat:incr() GameHelper.playerLeaderCard.stats.pointsToAllocate:decr() GameHelper.playerLeaderCard.stats.pointsToAllocate:decr() end end table.insert(tweaksStatsArr[1],attackUpButtonGUI) local attackDownButtonGUI=GUIHelper:CreateButtonWidget("attackDownButtonGUI",createLStatsATKGUI.x+2,createLStatsATKGUI.y+createLStatsATKGUI.h-11,16,9,glBackgroundWithBorderClickableGUIStyle,screen,"\\/") attackDownButtonGUI:addParent(createLStatsATKGUI) attackDownButtonGUI.onCleanRelease=function(ref) local stat=GameHelper.playerLeaderCard.stats.attack if stat.cur>0 then GameHelper.playerLeaderCard.stats.pointsToAllocate:incr() GameHelper.playerLeaderCard.stats.pointsToAllocate:incr() GUIHelper.InteractableActiveControlBaseClickFunc(ref) stat:decr() stat.max=math.max(0,stat.max-1) end end table.insert(tweaksStatsArr[2],attackDownButtonGUI) local createLStatsHPGUI=GUIHelper:CreateGUIFrame("createLStatsHPGUI",createLStatsATKGUI.x+createLStatsATKGUI.w+2,createLStatsATKGUI.y,20,32,glBackgroundWithBorderGUIBlackStyle) createLStatsHPGUI:addParent(glCreateLeaderCardStatsGUI) createLStatsHPGUI:Content(function(ref,x,y) y=y+ref.h/2-5 rect(x+0,y,ref.w,8,1) spr(257,x+ref.w-10,y,0) print(GameHelper.playerLeaderCard.stats.hp.cur,x+2,y+2,15) end) local hpUpButtonGUI=GUIHelper:CreateButtonWidget("hpUpButtonGUI",createLStatsHPGUI.x+2,createLStatsHPGUI.y+2,16,9,glBackgroundWithBorderClickableGUIStyle,screen,"/\\") hpUpButtonGUI:addParent(createLStatsATKGUI) hpUpButtonGUI.onCleanRelease=function(ref) if GameHelper.playerLeaderCard.stats.pointsToAllocate.cur>0 then local stat=GameHelper.playerLeaderCard.stats.hp stat.max=stat.max+RuleHelper.hpPerPoint stat.cur=stat.cur+RuleHelper.hpPerPoint GameHelper.playerLeaderCard.stats.pointsToAllocate:decr() GUIHelper.InteractableActiveControlBaseClickFunc(ref) end end table.insert(tweaksStatsArr[1],hpUpButtonGUI) local hpDownButtonGUI=GUIHelper:CreateButtonWidget("hpDownButtonGUI",createLStatsHPGUI.x+2,createLStatsHPGUI.y+createLStatsHPGUI.h-11,16,9,glBackgroundWithBorderClickableGUIStyle,screen,"\\/") hpDownButtonGUI:addParent(createLStatsATKGUI) hpDownButtonGUI.onCleanRelease=function(ref) local stat=GameHelper.playerLeaderCard.stats.hp if stat.cur>RuleHelper.hpPerPoint then GameHelper.playerLeaderCard.stats.pointsToAllocate:incr() GUIHelper.InteractableActiveControlBaseClickFunc(ref) stat.cur=math.max(RuleHelper.hpPerPoint,stat.cur-RuleHelper.hpPerPoint) stat.max=math.max(RuleHelper.hpPerPoint,stat.max-RuleHelper.hpPerPoint) end end table.insert(tweaksStatsArr[2],hpDownButtonGUI) local createLStatsARMORGUI=GUIHelper:CreateGUIFrame("createLStatsARMORGUI",createLStatsHPGUI.x+createLStatsHPGUI.w+2,createLStatsHPGUI.y,20,32,glBackgroundWithBorderGUIBlackStyle) createLStatsARMORGUI:addParent(glCreateLeaderCardStatsGUI) createLStatsARMORGUI:Content(function(ref,x,y) y=y+ref.h/2-5 rect(x+0,y,ref.w,8,7) spr(258,x+ref.w-10,y,0) print(GameHelper.playerLeaderCard.stats.armor.cur,x+2,y+2,0) end) local armorUPButtonGUI=GUIHelper:CreateButtonWidget("armorUPButtonGUI",createLStatsARMORGUI.x+2,createLStatsARMORGUI.y+2,16,9,glBackgroundWithBorderClickableGUIStyle,screen,"/\\") armorUPButtonGUI:addParent(createLStatsATKGUI) armorUPButtonGUI.onCleanRelease=function(ref) if GameHelper.playerLeaderCard.stats.pointsToAllocate.cur>0 then local stat=GameHelper.playerLeaderCard.stats.armor stat.max=stat.max+RuleHelper.armorPerPoint stat.cur=stat.cur+RuleHelper.armorPerPoint GameHelper.playerLeaderCard.stats.pointsToAllocate:decr() GUIHelper.InteractableActiveControlBaseClickFunc(ref) end end table.insert(tweaksStatsArr[1],armorUPButtonGUI) local armorDownButtonGUI=GUIHelper:CreateButtonWidget("armorDownButtonGUI",createLStatsARMORGUI.x+2,createLStatsARMORGUI.y+createLStatsARMORGUI.h-11,16,9,glBackgroundWithBorderClickableGUIStyle,screen,"\\/") armorDownButtonGUI:addParent(createLStatsATKGUI) armorDownButtonGUI.onCleanRelease=function(ref) local stat=GameHelper.playerLeaderCard.stats.armor if stat.cur>0 then GameHelper.playerLeaderCard.stats.pointsToAllocate:incr() GUIHelper.InteractableActiveControlBaseClickFunc(ref) stat.cur=math.max(0,stat.cur-RuleHelper.armorPerPoint) stat.max=math.max(0,stat.cur-RuleHelper.armorPerPoint) end end table.insert(tweaksStatsArr[2],armorDownButtonGUI) end glCreateLeaderCardTagsGUI=GUIHelper:CreateGUIFrame("glCreateLeaderCardTagsGUI",glCreateLeaderCardStatsGUI.x+glCreateLeaderCardStatsGUI.w+2,screen.y+10,166,110,glBackgroundWithBorderGUIBlackStyle) glCreateLeaderCardTagsGUI:addParent(screen) glCreateLeaderCardTagsGUI.tagsSelected=0 glCreateLeaderCardTagsGUI:Content(function(ref,x,y) if AchievementsHelper.CreateLeaderSelectTagsUnlocked then print("ADD TAGS: ".."("..glCreateLeaderCardTagsGUI.tagsSelected.."/6 TAGS)",x+1,y+1,11) print("("..GameHelper.playerLeaderCard.stats.pointsToAllocate.cur.." points left)",x+110,y+1,(GameHelper.playerLeaderCard.stats.pointsToAllocate.cur>0 and 14 or 11),false,1,true) else print("NOT UNLOCKED",x+1,y+1,10) print("Play twice to \nunlock adding TAGS",x+1,y+8,10,false,1,true) end end) glCreateLeaderCardTagsGUI.tagsGUI={} glCreateLeaderCardTagsGUI.tagsSelected=0 if AchievementsHelper.CreateLeaderSelectTagsUnlocked then GUIHelper:PopulateTagsSelection(glCreateLeaderCardTagsGUI) end --change avatar gui glCreateLeaderCardSpriteGUI=GUIHelper:CreateGUIFrame("glCreateLeaderCardSpriteGUI",screen.x+2,screen.y+10,68,22,glBackgroundWithBorderGUIBlackStyle) glCreateLeaderCardSpriteGUI:addParent(screen) glCreateLeaderCardSpriteGUI:Content(function(ref,x,y) rectb(x+1,y+1,18,18,1) spr(GameHelper.playerLeaderCard.sprite,x+2,y+2,0,1,0,0,2,2) end) local changeAvatarButtonGUI=GUIHelper:CreateButtonWidget("changeAvatarButtonGUI",glCreateLeaderCardSpriteGUI.x+21,glCreateLeaderCardSpriteGUI.y+3,45,15,glBackgroundWithBorderClickable2GUIStyle,screen,"CHANGE YOUR\nUNIT AVATAR",true) changeAvatarButtonGUI:addParent(glCreateLeaderCardSpriteGUI) changeAvatarButtonGUI.onCleanRelease=function(ref) glChangeAvatarFrameGUI:show() glChangeAvatarFrameGUI:allToFront() end glChangeAvatarFrameGUI=GUIHelper:CreateGUIFrame("glChangeAvatarFrameGUI",0,0,glScreenPixelWidth,glScreenPixelHeight,glBackgroundWithBorderGUIBlackStyle) glChangeAvatarFrameGUI:Content(function(ref,x,y) print("SELECT AVATAR FOR YOUR LEADER UNIT:",x+1,y+1,5) end) local sprites={2,4,164,168,194,196,198,170,138,263,265} for i=0,2 do for j=0,7 do table.insert(sprites,32+j*2+i*32) end end for i=0,7 do for j=0,7 do table.insert(sprites,288+j*2+i*32) end end local spritesGUI={} for i=0,4 do for j=0,9 do local spriteOptionGUI=GUIHelper:CreateGUIFrame("spriteOptionGUI",glChangeAvatarFrameGUI.x+11+20*j+j*2,glChangeAvatarFrameGUI.y+12+20*i+i*2,20,20,glBackgroundWithBorderClickableGUIStyle) spriteOptionGUI:addParent(glChangeAvatarFrameGUI) local sprID=sprites[i*10+j+1] spriteOptionGUI.sprID=sprID if sprID==GameHelper.playerLeaderCard.sprite then spriteOptionGUI.border=glGUIFrameStyleActiveOKCard.border end spriteOptionGUI:Content(function(ref,x,y) spr(ref.sprID,x+1,y+1,-1,1,0,0,2,2) end) spriteOptionGUI.onCleanRelease=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref) GameHelper.playerLeaderCard.sprite=ref.sprID foreach(ref.allButtons,function(button) button.border=glBackgroundWithBorderClickableGUIStyle.border end) ref.border=glGUIFrameStyleActiveOKCard.border GameHelper:SaveAvatarToPMEM() glChangeAvatarFrameGUI:hide() end table.insert(spritesGUI,spriteOptionGUI) spriteOptionGUI.allButtons=spritesGUI end end glConfirmAvatarButtonGUI=GUIHelper:CreateButtonWidget("glConfirmAvatarButtonGUI",glChangeAvatarFrameGUI:getCenterX()-20,glChangeAvatarFrameGUI.y+glChangeAvatarFrameGUI.h-11,40,9,glBackgroundWithBorderClickableGUIStyle,glChangeAvatarFrameGUI,"OK") glConfirmAvatarButtonGUI:addParent(glChangeAvatarFrameGUI) glConfirmAvatarButtonGUI.onCleanRelease=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref) GameHelper:SaveAvatarToPMEM() glChangeAvatarFrameGUI:hide() end glChangeAvatarFrameGUI:hide() glConfirmCreatedLeaderGUI=GUIHelper:CreateButtonWidget("glConfirmCreatedLeaderGUI",screen:getCenterX()-20,screen.y+screen.h-11,40,9,glBackgroundWithBorderClickableGUIStyle,screen,"OK") glConfirmCreatedLeaderGUI:addParent(screen) glConfirmCreatedLeaderGUI.onCleanRelease=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref) GameHelper.finishedCreatingLeader=true GameHelper.playerLeaderFormula=GameHelper.playerLeaderCard:DeepCopy() glCreateLeaderCardGUI:hide() end glBackFromCreatedLeaderGUI=GUIHelper:CreateButtonWidget("glBackFromCreatedLeaderGUI",screen:getCenterX()+30,screen.y+screen.h-11,40,9,glBackgroundWithBorderClickableGUIStyle,screen,"BACK") glBackFromCreatedLeaderGUI:addParent(screen) glBackFromCreatedLeaderGUI.onCleanRelease=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref) reset() end glCreateLeaderCardGUI=screen end function GUICreator:RemoveLeaderCreationScreen() if glCreateLeaderCardGUI then Logger:Debug("removing LEADER CREATION screen",glMsgType.GUI) glCreateLeaderCardGUI:remove() glCreateLeaderCardGUI=nil else Logger:Debug("LEADER CREATION screen is already deleted!",glMsgType.GUI) end end function GUICreator:CreateGameOptionsScreen() if glGUIFrameGameOptions then Logger:Debug("OPTIONS screen already exists!",glMsgType.GUI) return end Logger:Debug("Creating OPTIONS screen",glMsgType.GUI) local screen=GUIHelper:CreateGUIFrame("glGUIFrameGameOptions",-1,-1,glScreenPixelWidth+2,glScreenPixelHeight+2,glBackgroundWithBorderGUIBlackStyle) screen:Content(function(ref,x,y) rectb(x,y,ref.w-2,ref.h-2,1) print("OPTIONS",x+2,y+2,5) y=y-40 print("Delay before showing full card preview:",x+4,y+51,4) print(GameHelper.delayBeforeShowingFullCard,x+30,y+61,12) print("Delay before showing tooltips:",x+4,y+71,4) print(GameHelper.delayBeforeShowingTooltips,x+30,y+81,12) print("Animation speed:",x+4,y+91,4) print("x"..GameHelper.animationSpeed,x+30,y+101,12) print("AI speed:",x+4,y+111,4) print("x"..AIHelper.AISpeedMult,x+30,y+121,12) end) local mouseContFunc=function() GameHelper.controlScheme=1 end local touchContFunc=function() GameHelper.controlScheme=2 end local isTouchControls=GameHelper.controlScheme==2 if isTouchControls then touchContFunc() else mouseContFunc() end local y1=20 local delayLeftButton=GUIHelper:CreateButtonWidget("glGUIFrameGameOptions_delayLeftButton",screen.x+10,screen.y+y1,16,9,glBackgroundWithBorderClickableGUIStyle,screen," <") delayLeftButton:addParent(screen) delayLeftButton.onCleanRelease=function(ref) GameHelper.delayBeforeShowingFullCard=math.max(0.5,math.min(6,GameHelper.delayBeforeShowingFullCard-0.5)) end local delayRightButton=GUIHelper:CreateButtonWidget("glGUIFrameGameOptions_delayRightButton",screen.x+50,screen.y+y1,16,9,glBackgroundWithBorderClickableGUIStyle,screen," >") delayRightButton:addParent(screen) delayRightButton.onCleanRelease=function(ref) GameHelper.delayBeforeShowingFullCard=math.max(0.5,math.min(6,GameHelper.delayBeforeShowingFullCard+0.5)) end local tooltipsLeftButton=GUIHelper:CreateButtonWidget("glGUIFrameGameOptions_tooltipsLeftButton",screen.x+10,screen.y+y1+20,16,9,glBackgroundWithBorderClickableGUIStyle,screen," <") tooltipsLeftButton:addParent(screen) tooltipsLeftButton.onCleanRelease=function(ref) GameHelper.delayBeforeShowingTooltips=math.max(0.5,math.min(6,GameHelper.delayBeforeShowingTooltips-0.5)) end local tooltipsRightButton=GUIHelper:CreateButtonWidget("glGUIFrameGameOptions_tooltipsRightButton",screen.x+50,screen.y+y1+20,16,9,glBackgroundWithBorderClickableGUIStyle,screen," >") tooltipsRightButton:addParent(screen) tooltipsRightButton.onCleanRelease=function(ref) GameHelper.delayBeforeShowingTooltips=math.max(0.5,math.min(6,GameHelper.delayBeforeShowingTooltips+0.5)) end local animSpeedLeftButton=GUIHelper:CreateButtonWidget("glGUIFrameGameOptions_animSpeedLeftButton",screen.x+10,screen.y+y1+40,16,9,glBackgroundWithBorderClickableGUIStyle,screen," <") animSpeedLeftButton:addParent(screen) animSpeedLeftButton.onCleanRelease=function(ref) GameHelper.animationSpeed=math.max(1,math.min(3,GameHelper.animationSpeed-1)) end local animSpeedRightButton=GUIHelper:CreateButtonWidget("glGUIFrameGameOptions_animSpeedRightButton",screen.x+50,screen.y+y1+40,16,9,glBackgroundWithBorderClickableGUIStyle,screen," >") animSpeedRightButton:addParent(screen) animSpeedRightButton.onCleanRelease=function(ref) GameHelper.animationSpeed=math.max(1,math.min(3,GameHelper.animationSpeed+1)) end local aiSpeedMultLeftButton=GUIHelper:CreateButtonWidget("glGUIFrameGameOptions_aiSpeedMultLeftButton",screen.x+10,screen.y+y1+60,16,9,glBackgroundWithBorderClickableGUIStyle,screen," <") aiSpeedMultLeftButton:addParent(screen) aiSpeedMultLeftButton.onCleanRelease=function(ref) AIHelper.AISpeedMult=math.max(1,math.min(3,AIHelper.AISpeedMult-1)) AIHelper.aiTimeBetweenActionsInSecs=1.6-(AIHelper.AISpeedMult-2)*0.5 end local aiSpeedMultRightButton=GUIHelper:CreateButtonWidget("glGUIFrameGameOptions_aiSpeedMultRightButton",screen.x+50,screen.y+y1+60,16,9,glBackgroundWithBorderClickableGUIStyle,screen," >") aiSpeedMultRightButton:addParent(screen) aiSpeedMultRightButton.onCleanRelease=function(ref) AIHelper.AISpeedMult=math.max(1,math.min(3,AIHelper.AISpeedMult+1)) AIHelper.aiTimeBetweenActionsInSecs=1.6-(AIHelper.AISpeedMult-2)*0.5 end local closeFrameButton= GUIHelper:CreateButtonWidget("closeFrameButton",screen.x+179,screen.y+screen.h-12,60,9,glBackgroundWithBorderClickableGUIStyle,screen,"Close") closeFrameButton:addParent(screen) closeFrameButton.onCleanRelease=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref,false,true) glGUIFrameGameOptions:hide() gameOptionsButtonClicked=false GameHelper:SaveBaseOptionsToPMEM() GameHelper:SaveMoreOptionsToPMEM() GUIHelper.gameOptionsOpened=false end abandonRunButton= GUIHelper:CreateButtonWidget("abandonRunButton",screen.x+4,screen.y+screen.h-12,85,9,glBackgroundWithBorderClickableGUIStyle,screen,"ABANDON MATCH") abandonRunButton:addParent(screen) abandonRunButton.onCleanRelease=function(ref) if gameInitialized then GUIHelper.InteractableActiveControlBaseClickFunc(ref) GameHelper:ForceEndMatch(false) closeFrameButton:onCleanRelease() end end glGUIFrameGameOptions=screen end function GUICreator:RemoveGameOptionScreen() if glGUIFrameGameOptions then Logger:Debug("removing OPTIONS screen",glMsgType.GUI) glGUIFrameGameOptions:remove() glGUIFrameGameOptions=nil else Logger:Debug("OPTIONS screen is already deleted!",glMsgType.GUI) end end function GUICreator:CreateChangelogScreen() if glGUIMainMenuChangelogScreen then Logger:Debug("CHANGELOG screen already exists!",glMsgType.GUI) end Logger:Debug("Creating CHANGELOG screen",glMsgType.GUI) local screen=GUIHelper:CreateGUIFrame("glGUIMainMenuChangelogScreen",-1,-1,glScreenPixelWidth+2,glScreenPixelHeight+2,glBackgroundWithBorderGUIBlackStyle) screen:Content(function(ref,x,y) print("CHANGELOG: ",x+2,y+2,5) local i=1 foreach(glVersionBlurbTextArray,function(txt) print(txt,x+2,y+2+8*i,11,false,1,true) i=i+1 end) rectb(x,y,ref.w-2,ref.h-2,1) end) glGUIMainMenuChangelogScreenButtonCloseFrame= GUIHelper:CreateButtonWidget("glGUIMainMenuChangelogScreenButtonCloseFrame",screen.x+179,screen.y+screen.h-12,60,9,glBackgroundWithBorderClickableGUIStyle,screen,"Close") glGUIMainMenuChangelogScreenButtonCloseFrame:addParent(screen) glGUIMainMenuChangelogScreenButtonCloseFrame.onCleanRelease=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref,false,true) glGUIMainMenuChangelogScreen:hide() end glGUIMainMenuChangelogScreen=screen end function GUICreator:CreateCreditsScreen() if glGUIMainMenuCreditsScreen then Logger:Debug("CREDITS screen already exists!",glMsgType.GUI) end Logger:Debug("Creating CREDITS screen",glMsgType.GUI) glGUIMainMenuCreditsScreen = GUIHelper:CreateGUIFrame("glGUIMainMenuCreditsScreen",-1,-1,glScreenPixelWidth+2,glScreenPixelHeight+2,glBackgroundWithBorderGUIBlackStyle) glGUIMainMenuCreditsScreen:Content(function(ref,x,y) print("CREDITS: ",x+2,y+2,5) local i=1 foreach(glCreditsBlurbTextArray,function(txt) print(" "..txt,x+2,y+2+8*i,11,false,1,false) i=i+1 end) rectb(x,y,ref.w-2,ref.h-2,1) end) glGUIMainMenuCreditsScreenButtonCloseFrame= GUIHelper:CreateButtonWidget("glGUIMainMenuCreditsScreenButtonCloseFrame",glGUIMainMenuCreditsScreen.x+179,glGUIMainMenuCreditsScreen.y+glGUIMainMenuCreditsScreen.h-12,60,9,glBackgroundWithBorderClickableGUIStyle,glGUIMainMenuChangelogScreen,"Close") glGUIMainMenuCreditsScreenButtonCloseFrame:addParent(glGUIMainMenuCreditsScreen) glGUIMainMenuCreditsScreenButtonCloseFrame.onCleanRelease=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref,false,true) glGUIMainMenuCreditsScreen:hide() end end function GUICreator:CreateUnlocksScreen() if glGUIMainMenuUnlocksScreen then Logger:Debug("UNLOCKS screen already exists!",glMsgType.GUI) end Logger:Debug("Creating UNLOCKS screen",glMsgType.GUI) glGUIMainMenuUnlocksScreen = GUIHelper:CreateGUIFrame("glGUIMainMenuUnlocksScreen",-1,-1,glScreenPixelWidth+2,glScreenPixelHeight+2,glBackgroundWithBorderGUIBlackStyle) glGUIMainMenuUnlocksScreen:Content(function(ref,x,y) print("UNLOCKS ",x+2,y+2,5) print("(PLAYED: "..GameHelper.numOfPlayingGameMode.."/12".." AND WON "..GameHelper.numOfWinningGameMode.."/8 GAMES)",x+48,y+2,11,false,1,true) rectb(x,y,ref.w-2,ref.h-2,1) end) local decksN=0 local decksUnl=0 local decksText={} local specialN=0 local specialUnl=0 local specialText={} local tagN=0 local tagUnl=0 local tagsText={} local artifactN=0 local artifactUnl=0 local artifactText={} foreach(AchievementsHelper.unlocksData,function(data) if data.type=="DECK" then decksN=decksN+1 local str="" if data.unlocked then decksUnl=decksUnl+1 str="^11"..data.name.." unlocked by "..(data.req=="PLAY" and "playing " or "winning ")..data.reqVal.." runs" else str="^15???? will be unlocked by "..(data.req=="PLAY" and "playing " or "winning ")..data.reqVal.." runs" end table.insert(decksText,str) elseif data.type=="MECHANICS" then specialN=specialN+1 local str="" if data.unlocked then specialUnl=specialUnl+1 str="^11"..data.name.." unlocked by "..(data.req=="PLAY" and "playing " or "winning ")..data.reqVal.." runs" else str="^15???? will be unlocked by "..(data.req=="PLAY" and "playing " or "winning ")..data.reqVal.." runs" end table.insert(specialText,str) elseif data.type=="TAG" then tagN=tagN+1 local str="" if data.unlocked then tagUnl=tagUnl+1 str="^11"..data.name.." unlocked by "..(data.req=="PLAY" and "playing " or "winning ")..data.reqVal.." runs" else str="^15???? will be unlocked by "..(data.req=="PLAY" and "playing " or "winning ")..data.reqVal.." runs" end table.insert(tagsText,str) elseif data.type=="ARTIFACT" then artifactN=artifactN+1 local str="" if data.unlocked then artifactUnl=artifactUnl+1 str="^11"..data.name.." unlocked by "..(data.req=="PLAY" and "playing " or "winning ")..data.reqVal.." runs" else local len=#data.name str="^15??? will be unlocked by "..(data.req=="PLAY" and "playing " or "winning ")..data.reqVal.." runs" end table.insert(artifactText,str) end end) glGUIFrameUnlocksDeckSummary = GUIHelper:CreateTextLogWithTitleInFoldableFrame("glGUIFrameUnlocksDeckSummary",glGUIMainMenuUnlocksScreen.x+3,glGUIMainMenuUnlocksScreen.y+10,glGUIMainMenuUnlocksScreen.w-6,67,"DECK UNLOCKS: "..decksUnl.."/"..decksN,true) glGUIFrameUnlocksDeckSummary:addParent(glGUIMainMenuUnlocksScreen) glGUIFrameUnlocksSpecialSummary = GUIHelper:CreateTextLogWithTitleInFoldableFrame("glGUIFrameUnlocksSpecialSummary",glGUIFrameUnlocksDeckSummary.x,glGUIFrameUnlocksDeckSummary.y+12,glGUIFrameUnlocksDeckSummary.w,39,"SPECIAL UNLOCKS: "..specialUnl.."/"..specialN,true) glGUIFrameUnlocksSpecialSummary:addParent(glGUIMainMenuUnlocksScreen) glGUIFrameUnlocksTagSummary = GUIHelper:CreateTextLogWithTitleInFoldableFrame("glGUIFrameUnlocksTagSummary",glGUIFrameUnlocksDeckSummary.x,glGUIFrameUnlocksSpecialSummary.y+12,glGUIFrameUnlocksDeckSummary.w,74,"TAG UNLOCKS: "..tagUnl.."/"..tagN,true) glGUIFrameUnlocksTagSummary:addParent(glGUIMainMenuUnlocksScreen) glGUIFrameUnlocksArtifactSummary = GUIHelper:CreateTextLogWithTitleInFoldableFrame("glGUIFrameUnlocksArtifactSummary",glGUIFrameUnlocksDeckSummary.x,glGUIFrameUnlocksTagSummary.y+12,glGUIFrameUnlocksDeckSummary.w,32,"ARTIFACT UNLOCKS: "..artifactUnl.."/"..artifactN,true) glGUIFrameUnlocksArtifactSummary:addParent(glGUIMainMenuUnlocksScreen) glGUIFrameUnlocksDeckSummary:ClickFoldButton() glGUIFrameUnlocksSpecialSummary:ClickFoldButton() glGUIFrameUnlocksTagSummary:ClickFoldButton() glGUIFrameUnlocksArtifactSummary:ClickFoldButton() glGUIFrameUnlocksDeckSummary:RegisterControlToMoveOnFoldAction(glGUIFrameUnlocksSpecialSummary) glGUIFrameUnlocksSpecialSummary:RegisterControlToMoveOnFoldAction(glGUIFrameUnlocksTagSummary) glGUIFrameUnlocksTagSummary:RegisterControlToMoveOnFoldAction(glGUIFrameUnlocksArtifactSummary) local textLog=glGUIFrameUnlocksDeckSummary.textLog foreach(decksText,function(str) GUIHelper:InsertUnparsedTextIntoTextGUIFrame(str,textLog) end) textLog=glGUIFrameUnlocksSpecialSummary.textLog foreach(specialText,function(str) GUIHelper:InsertUnparsedTextIntoTextGUIFrame(str,textLog) end) textLog=glGUIFrameUnlocksTagSummary.textLog foreach(tagsText,function(str) GUIHelper:InsertUnparsedTextIntoTextGUIFrame(str,textLog) end) textLog=glGUIFrameUnlocksArtifactSummary.textLog foreach(artifactText,function(str) GUIHelper:InsertUnparsedTextIntoTextGUIFrame(str,textLog) end) local y1=20 local y2=12 local resetFunc=function() for i=0,255 do pmem(i,0) end reset() end glGUIResetProgressOption=GUIHelper:CreateButtonWidget("glGUIResetProgressOption",2,glGUIMainMenuUnlocksScreen.y+y1+y2*9-3,90,10,glGUIFrameStyleActiveOKCard,glFullScreenMenuBackground,"RESET SAVE DATA") glGUIResetProgressOption:addParent(glGUIMainMenuUnlocksScreen) glGUIResetProgressOption.onCleanRelease=resetFunc glGUICheatProgressOption=GUIHelper:CreateButtonWidget("glGUICheatProgressOption",glGUIResetProgressOption.x+glGUIResetProgressOption.w+2,glGUIMainMenuUnlocksScreen.y+y1+y2*9-3,50,10,glGUIFrameStyleActiveOKCard,glFullScreenMenuBackground,"CHEATS") glGUICheatProgressOption:addParent(glGUIMainMenuUnlocksScreen) glGUICheatProgressOption.onCleanRelease=function(ref) glGUIMainMenuCheatsScreen:show() glGUIMainMenuCheatsScreen:allToFront() GUIHelper.InteractableActiveControlBaseClickFunc(ref) end glGUIMainMenuUnlocksScreenButtonCloseFrame= GUIHelper:CreateButtonWidget("glGUIMainMenuUnlocksScreenButtonCloseFrame",glGUIMainMenuUnlocksScreen.x+179,glGUIMainMenuUnlocksScreen.y+glGUIMainMenuUnlocksScreen.h-12,60,9,glBackgroundWithBorderClickableGUIStyle,glGUIMainMenuUnlocksScreen,"Close") glGUIMainMenuUnlocksScreenButtonCloseFrame:addParent(glGUIMainMenuUnlocksScreen) glGUIMainMenuUnlocksScreenButtonCloseFrame.onCleanRelease=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref,false,true) glGUIMainMenuUnlocksScreen:hide() end end function GUICreator:CreateCheatsScreen() if glGUIMainMenuCheatsScreen then Logger:Debug("CHEATS screen already exists!",glMsgType.GUI) end Logger:Debug("Creating CHEATS screen",glMsgType.GUI) glGUIMainMenuCheatsScreen = GUIHelper:CreateGUIFrame("glGUIMainMenuCheatsScreen",-1,-1,glScreenPixelWidth+2,glScreenPixelHeight+2,glBackgroundWithBorderGUIBlackStyle) glGUIMainMenuCheatsScreen:Content(function(ref,x,y) print("CHEATS",x+2,y+2,5) rectb(x,y,ref.w-2,ref.h-2,1) print("You try content without unlocking, but it will reset after game restart.",x+2,y+10,4,false,1,true) end) local y1=20 local y2=12 local decksFunc=function(ref) for i=1,99 do local deckData=AchievementsHelper.unlocksData["DECK"..i] if deckData then deckData.unlocked=true else break end end AchievementsHelper.unlocksData.CHANGE_LEADER_AVATAR.unlocked=true AchievementsHelper.unlocksData.CHANGE_LEADER_STATS.unlocked=true AchievementsHelper.unlocksData.CHANGE_LEADER_TAGS.unlocked=true GameHelper.finishedCreatingLeader=false GUIHelper.InteractableActiveControlBaseClickFunc(ref) end local tagsFunc=function() for i=1,99 do local tagData=AchievementsHelper.unlocksData["TAG"..i] if tagData then tagData.unlocked=true else break end end GUIHelper.InteractableActiveControlBaseClickFunc(ref) end local artifactsFunc=function() for i=1,99 do local tagData=AchievementsHelper.unlocksData["TREASURE"..i] if tagData then tagData.unlocked=true else break end end GUIHelper.InteractableActiveControlBaseClickFunc(ref) end local emptyFunc=function() end local unlockAllFunc=function() decksFunc() tagsFunc() artifactsFunc() glGUIMainMenuCheatsScreen:hide() end local opt=GUIHelper:CreateButtonWidget("glGUIMainMenuUnlocksScreen_1",4,glGUIMainMenuUnlocksScreen.y+y1,180,10,glGUIFrameStyleActiveOKCard,glFullScreenMenuBackground,"UNLOCK ALL CARDS") opt:addParent(glGUIMainMenuCheatsScreen) opt.onCleanRelease=decksFunc opt=GUIHelper:CreateButtonWidget("glGUIMainMenuUnlocksScreen_2",4,glGUIMainMenuUnlocksScreen.y+y1+y2,180,10,glGUIFrameStyleActiveOKCard,glFullScreenMenuBackground,"UNLOCK ALL DECKS") opt:addParent(glGUIMainMenuCheatsScreen) opt.onCleanRelease=decksFunc opt=GUIHelper:CreateButtonWidget("glGUIMainMenuUnlocksScreen_3",4,glGUIMainMenuUnlocksScreen.y+y1+y2*2,180,10,glGUIFrameStyleActiveOKCard,glFullScreenMenuBackground,"UNLOCK ALL TAGS") opt:addParent(glGUIMainMenuCheatsScreen) opt.onCleanRelease=tagsFunc opt=GUIHelper:CreateButtonWidget("glGUIMainMenuUnlocksScreen_4",4,glGUIMainMenuUnlocksScreen.y+y1+y2*3,180,10,glGUIFrameStyleActiveOKCard,glFullScreenMenuBackground,"UNLOCK ALL ARTIFACTS") opt:addParent(glGUIMainMenuCheatsScreen) opt.onCleanRelease=artifactsFunc opt=GUIHelper:CreateButtonWidget("glGUIMainMenuUnlocksScreen_5",4,glGUIMainMenuUnlocksScreen.y+y1+y2*7,180,10,glGUIFrameStyleActiveOKCard,glFullScreenMenuBackground,"UNLOCK ALL THE THINGS!!!!") opt:addParent(glGUIMainMenuCheatsScreen) opt.onCleanRelease=unlockAllFunc glGUIMainMenuCheatsScreenButtonCloseFrame= GUIHelper:CreateButtonWidget("glGUIMainMenuCheatsScreenButtonCloseFrame",glGUIMainMenuUnlocksScreen.x+179,glGUIMainMenuUnlocksScreen.y+glGUIMainMenuUnlocksScreen.h-12,60,9,glBackgroundWithBorderClickableGUIStyle,glGUIMainMenuCheatsScreen,"Close") glGUIMainMenuCheatsScreenButtonCloseFrame:addParent(glGUIMainMenuCheatsScreen) glGUIMainMenuCheatsScreenButtonCloseFrame.onCleanRelease=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref,false,true) glGUIMainMenuCheatsScreen:hide() end glGUIMainMenuUnlocksScreen:hide() glGUIMainMenuCheatsScreen:hide() end function GUICreator:CreateMainMenuScreen() if glFullScreenMenuBackground then Logger:Debug("MAIN MENU screen already exists!",glMsgType.GUI) end Logger:Debug("Creating MAIN MENU screen",glMsgType.GUI) glFullScreenMenuBackground= GUIHelper:CreateGUIFrame("glFullScreenMenuBackground",0,0,glScreenPixelWidth,glScreenPixelHeight,glBackgroundStaticVioletGUIStyle) InitSeed(math.random(999999),true) local s22=glVersionBlurbTextArray[1] glFullScreenMenuBackground:Content(function(ref,x,y) local scrY=4 local s="SLEEPLESS CARDS" local s34="CURRENTLY ONLY MOUSE SUPPORTED!" local s35=glGameSeed and glGameSeed or 0 local l=print(s,-1000,-1000,1,false,2) print(s,glScreenPixelWidth/2-l/2,scrY,6,false,2) rect(0,scrY+11,glScreenPixelWidth,7,6) l=print(s22,-1000,-1000,1,false,1,true) print(s22,glScreenPixelWidth/2-l/2,scrY+12,1,false,1,true) spr(14,glScreenPixelWidth-16,glScreenPixelHeight/2-16,-1,1,0,0,2,2) scrY=104 local unlock=AchievementsHelper.closestUnlocksData[1] local unlock2=AchievementsHelper.closestUnlocksData[2] if GameHelper.numOfPlayingGameMode>0 and (unlock or unlock2) then local s42=(unlock.req=="PLAY" and "Play" or "Win").." game to unlock "..unlock.name local s43=(unlock2 and ((unlock2.req=="PLAY" and "Play" or "Win").." game to unlock "..unlock2.name) or "") local visibleS43=s43~="" if not visibleS43 then scrY=scrY+4 end l=print(s42,-1000,-1000,1) l=math.max(170,l) local x=glScreenPixelWidth/2-l/2 rect(0,scrY-2,glScreenPixelWidth,visibleS43 and 15 or 9,6) print(s42,x,scrY,1) l=print(s43,-1000,-1000,1) x=glScreenPixelWidth/2-l/2 print(s43,x,scrY+6,1) end scrY=125 if s34 then rect(0,scrY,glScreenPixelWidth,22,0) l=(#s34)*6 print(s34,glScreenPixelWidth/2-l/2,scrY+3,6) l=(#tostring(s35))*4 print(s35,glScreenPixelWidth-l,scrY+3,6,false,1,true) end end) Logger:Info("------------",glMsgType.INIT_BASE) Logger:Info("RUNNING VERSION:",glMsgType.INIT_BASE) Logger:Info(s22,glMsgType.INIT_BASE) Logger:Info("------------",glMsgType.INIT_BASE) local startFunc=function() if not GameHelper.playedTutorial then glTutorialDialog=GUIHelper:CreateTutorialDialog(function() end,{"","Hey!","","It looks like you","didn't played tutorial yet!","","^14I really recommend playing it","before starting the run!",""}) GameHelper.playedTutorial=1 GameHelper:SaveMoreOptionsToPMEM() else GameHelper.tutorialPhase=-10 InitGameGUI() InitGameLogic() if AchievementsHelper.CreateLeaderScreenUnlocked then glCreateLeaderCardGUI:show() end GUICreator:RemoveMainMenuScreens() end end local tutorialFunc=function() local debug=glDebugMode GameHelper.tutorialPhase=debug and 40 or 10 InitGameGUI() InitGameLogic() end local optionFunc=function() GUIHelper.InteractableActiveControlBaseClickFunc(glGUIFrameGameOptions) glGUIFrameGameOptions:allToFront() glGUIFrameGameOptions:show() end local unlocksFunc=function() GUIHelper.InteractableActiveControlBaseClickFunc(glGUIMainMenuUnlocksScreen) glGUIMainMenuUnlocksScreen:allToFront() glGUIMainMenuUnlocksScreen:show() end local changelogFunc=function() GUIHelper.InteractableActiveControlBaseClickFunc(glGUIMainMenuChangelogScreen) glGUIMainMenuChangelogScreen:allToFront() glGUIMainMenuChangelogScreen:show() end local creditsFunc=function() GUIHelper.InteractableActiveControlBaseClickFunc(glGUIMainMenuCreditsScreen) glGUIMainMenuCreditsScreen:allToFront() glGUIMainMenuCreditsScreen:show() end local mouseContFunc=function() GameHelper:LoadOptionsFromPMEM() GameHelper:LoadMoreOptionsFromPMEM() GameHelper.controlScheme=1 GameHelper:SaveBaseOptionsToPMEM() GameHelper:SaveMoreOptionsToPMEM() reset() end local touchContFunc=function() GameHelper:LoadOptionsFromPMEM() GameHelper:LoadMoreOptionsFromPMEM() GameHelper.controlScheme=2 GameHelper:SaveBaseOptionsToPMEM() GameHelper:SaveMoreOptionsToPMEM() reset() end local scrY=31 local str2="TUTORIAL" local tutButton=GUIHelper:CreateButtonWidget("glFullScreenMenuBackground_tutorial",glScreenPixelWidth/2-45,scrY,90,10,glGUIFrameStyleActiveOKCard,glFullScreenMenuBackground,str2) tutButton:addParent(glFullScreenMenuBackground) tutButton.onCleanRelease=tutorialFunc local str1="START RUN" local startButton=GUIHelper:CreateButtonWidget("glFullScreenMenuBackground_startRun",glScreenPixelWidth/2-45,scrY+13*1,90,10,glGUIFrameStyleActiveOKCard,glFullScreenMenuBackground,str1) startButton:addParent(glFullScreenMenuBackground) startButton.onCleanRelease=startFunc local str3="OPTIONS" local optionsButton=GUIHelper:CreateButtonWidget("glFullScreenMenuBackground_options",glScreenPixelWidth/2-45,scrY+13*2,90,10,glGUIFrameStyleActiveOKCard,glFullScreenMenuBackground,str3) optionsButton:addParent(glFullScreenMenuBackground) optionsButton.onCleanRelease=optionFunc local str4="C\nH\nA\nN\nG\nE\nL\nO\nG" local changelogButton=GUIHelper:CreateButtonWidget("glFullScreenMenuBackground_changelog",-1,32,10,57,glGUIFrameStyleActiveOKCard,glFullScreenMenuBackground,str4) changelogButton:addParent(glFullScreenMenuBackground) changelogButton.onCleanRelease=changelogFunc local str5="UNLOCKS" local unlocksButton=GUIHelper:CreateButtonWidget("glFullScreenMenuBackground_unlocks",glScreenPixelWidth/2-45,scrY+13*3,90,10,glGUIFrameStyleActiveOKCard,glFullScreenMenuBackground,str5) unlocksButton:addParent(glFullScreenMenuBackground) unlocksButton.onCleanRelease=unlocksFunc local str5="CREDITS" local creditsButton=GUIHelper:CreateButtonWidget("glFullScreenMenuBackground_credits",glScreenPixelWidth/2-45,scrY+13*4,90,10,glGUIFrameStyleActiveOKCard,glFullScreenMenuBackground,str5) creditsButton:addParent(glFullScreenMenuBackground) creditsButton.onCleanRelease=creditsFunc GameHelper:LoadOptionsFromPMEM() GameHelper:LoadMoreOptionsFromPMEM() end function GUICreator:CreateChangeSeedScreen() local scenario=GUIScenarioCreator:CreateScenario(GUIScenarioCreator.scenarioType.CHOOSE_SEED) GUIScenarioQueueSystem:RegisterScenario(scenario) end function GUICreator:CreateMainMenuScreens() GUICreator:CreateChangelogScreen() GUICreator:CreateCreditsScreen() GUICreator:CreateUnlocksScreen() GUICreator:CreateCheatsScreen() GUICreator:CreateMainMenuScreen() if glDebugMode then GUICreator:CreateChangeSeedScreen() end end function GUICreator:RemoveMainMenuScreens() if glGUIMainMenuChangelogScreen then Logger:Debug("removing CHANGELOG screen",glMsgType.GUI) glGUIMainMenuChangelogScreen:remove() glGUIMainMenuChangelogScreen=nil else Logger:Debug("CHANGELOG screen is already deleted!",glMsgType.GUI) end if glGUIMainMenuCreditsScreen then Logger:Debug("removing CREDITS screen",glMsgType.GUI) glGUIMainMenuCreditsScreen:remove() glGUIMainMenuCreditsScreen=nil else Logger:Debug("CREDITS screen is already deleted!",glMsgType.GUI) end if glGUIMainMenuUnlocksScreen then Logger:Debug("removing UNLOCKS screen",glMsgType.GUI) glGUIMainMenuUnlocksScreen:remove() glGUIMainMenuUnlocksScreen=nil else Logger:Debug("UNLOCKS screen is already deleted!",glMsgType.GUI) end if glGUIMainMenuCheatsScreen then Logger:Debug("removing CHEATS screen",glMsgType.GUI) glGUIMainMenuCheatsScreen:remove() glGUIMainMenuCheatsScreen=nil else Logger:Debug("CHEATS screen is already deleted!",glMsgType.GUI) end if glFullScreenMenuBackground then Logger:Debug("removing MAIN SCREEN screen",glMsgType.GUI) glFullScreenMenuBackground:remove() glFullScreenMenuBackground=nil else Logger:Debug("MAIN SCREEN screen is already deleted!",glMsgType.GUI) end end -- GUIHELPER CLASS GUIHelper = {} GUIHelper.__index = GUIHelper GUIHelper.id=0 function GUIHelper:HoverMouseOverElement(element) glSimulatedMouse.x=element.x+1 glSimulatedMouse.y=element.y+1 end function GUIHelper:CreateGUIFrame(nameID,x,y,w,h,style) local frame=ticuare.element({ x = x, y = y, w = w, h = h, content ={ w = w, h = h, wrap = true }, }) frame.id=GUIHelper.id GUIHelper.id=self.id+1 frame.nameID=nameID or frame.id frame.hide=GUIHelper.HideFunc frame.isHidden=GUIHelper.IsHiddenFunc frame.isShown=GUIHelper.IsShownFunc frame.show=GUIHelper.ShowFunc frame.makeVisible=GUIHelper.MakeGUIElementVisibleWithFX frame.allToFront=GUIHelper.FrameAllToFrontFunc frame.children={} frame.controlsTable={} frame.addChild=GUIHelper.AddChild frame.addParent=GUIHelper.AddParent frame.remove=GUIHelper.remove frame.registerNewRow= GUIHelper.RegisterNewRow frame.registerChildToCurrentRow=GUIHelper.RegisterChildToCurrentRow frame.getCenterX=function(ref) return ref.x+ref.w/2 end frame.getCenterY=function(ref) return ref.y+ref.h/2 end frame.getRightX=function(ref) return ref.x+ref.w end frame.getDownY=function(ref) return ref.y+ref.h end frame:hide() frame:show() if style then return frame:style(style) end return frame end function GUIHelper.MakeGUIElementVisibleWithFX(control,delayInSec) AsyncQueueLogicHelper:AddToQueue(function(data) local ctrl=data.control if ctrl then ParticleHelper:CreateSummoningUnitFX(ctrl:getCenterX(),ctrl.y+ctrl.h) ctrl:visible(true) SfxHelper:PlaySFX(glSFXGUIControlAppeared,nil,30) end end,{control=control},delayInSec) end function GUIHelper.remove(ref) if ref.isRemoved then return end Logger:Trace("removing widget:"..(ref.text and ref.text or (ref.id and ref.id or "unknown")),glMsgType.GUI) ref.isRemoved=true local k=nil ref:hide() ref.parent=nil ref.text=nil ref.id=-1 if ref.children then foreach(ref.children,function(child) child:remove() end) end ticuare.remove(ref) ref.remove=nil ref.children=nil end function GUIHelper:AddAsChildToParent(child,parent) if not child or not parent then return end table.insert(parent.children,child) child.parent=parent child:anchor(parent) end function GUIHelper.AddParent(child,parent) GUIHelper:AddAsChildToParent(child,parent) end function GUIHelper.AddChild(parent,child) GUIHelper:AddAsChildToParent(child,parent) end function GUIHelper.RegisterNewRow(parent) table.insert(parent.controlsTable,{}) end function GUIHelper.RegisterChildToCurrentRow(parent,child) table.insert(parent.controlsTable[#parent.controlsTable],child) end function GUIHelper.ShowFunc(ref) if ref.y>1999 then ref.y=ref.oldY end end function GUIHelper.HideFunc(ref) if ref.y<2000 then ref.oldY=ref.y ref.y=2000 end end function GUIHelper.IsShownFunc(ref) return ref.y<2000 end function GUIHelper.IsHiddenFunc(ref) return ref.y>1999 end function GUIHelper.FrameAllToFrontFunc(ref,hzVal) ref:toFront(hzVal) if ref.children then foreach(ref.children,function(c) if c and not c.isRemoved then if c.children then c:allToFront(hzVal) else c:toFront(hzVal) end end end) end end function GUIHelper.SetControlOnHover(ref) if GameHelper.controlScheme<2 then ref.onHover=GUIHelper.onHover end end function GUIHelper.onHover(ref) if GameHelper.controlScheme<2 then GUIHelper.controlHoveredOver=ref end end function GUIHelper:InsertArrayIntoTextGUIFrame(arr,control) local s="" foreach(arr,function(text) if s~="" then s=s.."," end s=s.." "..text end) GUIHelper:InsertUnparsedTextIntoTextGUIFrame(s,control) end function GUIHelper:InsertUnparsedTextIntoTextGUIFrame(s,control,sprite) local arr=GUIHelper:ParseStringToArrayOfStringsForGUISpace(s,control,false) Logger:Debug(arr) control.resultTexts = control.resultTexts or {} foreach(arr,function(text) table.insert(control.resultTexts,(sprite and {text=text,spr=sprite} or text)) end) end function GUIHelper:ParseStringToArrayOfStringsForGUISpace(s, contentElement,smallFont,breakWordsInHalf) local n=string.len(s) local strArray={} local w=contentElement.w+10 local h=contentElement.h local charLen=smallFont and 4 or 5 local charsNum=w/charLen if charsNum>math.floor(charsNum) then charsNum=math.floor(charsNum)+1 end local words=string.split(s,"%s+") local lineCount=0 local currentLineStr="" foreach(words,function(word) local l=string.len(word) if string.sub(word,1,1)=="^" then l=l-3 end if (lineCount+l)>charsNum then table.insert(strArray,currentLineStr) lineCount=l+1 currentLineStr=word.." " else currentLineStr=currentLineStr..word.." " lineCount=lineCount+l+1 end end) if not table.contains(strArray,currentLineStr) then table.insert(strArray,currentLineStr) end return strArray end function GUIHelper:CreateButtonWidget(nameID,x,y,w,h,style,parent,text,smallFont,color) color = color or 15 local button=GUIHelper:CreateGUIFrame(nameID,x,y,w,h,style) if parent then button:addParent(parent) end button:Content(GUIHelper.ChoiceContentFunction) button.text=text button.smallFont=smallFont button.color=color or 15 return button end function GUIHelper.InteractableActiveControlBaseClickFunc(ref, dontPlaySound,playCancel) if not glMouse then Logger:Error("THERE IS NO MOUSE!") end if not dontPlaySound then SfxHelper:PlaySFX((playCancel and glSFXCancelGUIData or glSFXConfirmGUIData).id,(playCancel and glSFXCancelGUIData or glSFXConfirmGUIData).noteDef) end ParticleHelper:CreateMouseClickWithInteractionFX(glMouse.x,glMouse.y,0) end function GUIHelper.basicOptionClickFunc(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref) if ref.isCard then return end foreach(ref.parent.optionsGUI,function(guiFrame) guiFrame.colors=glBackgroundWithBorderClickableGUIStyle.colors guiFrame.border=glBackgroundWithBorderClickableGUIStyle.border guiFrame.titleColor=1 guiFrame.descGUI.color=10 if not ref.isCard then ref.border=glGUIFrameStyleActiveOKCard.border else ref.parent.border=glGUIFrameStyleActiveOKCard.border end end) ref.border=glBackgroundWithBorderClickableGUIStyleClicked.border ref.colors=glBackgroundWithBorderClickableGUIStyleClicked.colors ref.titleColor=6 if ref.descGUI then ref.descGUI.color=15 end end function GUIHelper.guiDialogOptionsReset(ref) ref.titleColor=6 if ref.descGUI then ref.descGUI.color=15 end ref.colors=glBackgroundWithBorderClickableGUIStyle.colors ref.border=glBackgroundWithBorderClickableGUIStyle.border end function GUIHelper:CreateGUIDialogWithXChoices(nameID,x,y,w,h,style,frameContentFunc,okClickFunc,numOfChoices,rows,choiceData,choiceYOffset) choiceYOffset=choiceYOffset or 0 local frame=GUIHelper:CreateGUIFrame(nameID.."_mainframe",x,y,w,h,style) frame:Content(frameContentFunc) frame.resetGUIFunc=function(ref) foreach(ref.optionsGUI,function(option) option:resetGUIFunc() end) end local okButton=GUIHelper:CreateButtonWidget(nameID.."_okButton",frame:getCenterX()-20,frame.y+frame.h-11,40,9,glBackgroundWithBorderClickableGUIStyle,frame,"OK") okButton:addParent(frame) okButton.onCleanRelease=okClickFunc frame.okButton=okButton local optionsGUI={} local w=(numOfChoices/rows) local h=rows --TODO: add support for rows not only columns! local option1=GUIHelper:CreateGUIFrame(nameID.."_frame0",frame.x+2,frame.y+9+choiceYOffset/h,((frame.w)-2*w)/w,(frame.h-24-choiceYOffset)/rows,glBackgroundWithBorderClickableGUIStyle) option1:addParent(frame) option1:Content(choiceData[1].optionContentFunc) option1.onCleanRelease=choiceData[1].optionClickFunc option1.basicOptionClickFunc=GUIHelper.basicOptionClickFunc option1.titleColor=6 option1.resetGUIFunc=GUIHelper.guiDialogOptionsReset local option1Desc=GUIHelper:CreateTextLogWidget(nameID.."_textLog0",option1.x+1,option1.y+4,option1.w-2,option1.h-10,glEmptyGUIStyle,true,nil) --make mouse ignore description control option1Desc.updateSelf=function() end option1Desc:addParent(option1) option1Desc.resultTexts={} option1Desc.color=15 GUIHelper:InsertUnparsedTextIntoTextGUIFrame(choiceData[1].optionTextStr,option1Desc) option1.descGUI=option1Desc table.insert(optionsGUI,option1) local prevOption=option1 for j=1,rows do for i=1,w do if not (j==1 and i==1) then local z=i+(j-1)*3 local option=GUIHelper:CreateGUIFrame(nameID.."_frame"..i,option1.x+(option1.w+1)*(i-1),option1.y+(option1.h+1)*(j-1),prevOption.w,prevOption.h,glBackgroundWithBorderClickableGUIStyle) option:addParent(frame) option:Content(choiceData[z].optionContentFunc) option.onCleanRelease=choiceData[z].optionClickFunc option.basicOptionClickFunc=GUIHelper.basicOptionClickFunc option.titleColor=6 option.resetGUIFunc=GUIHelper.guiDialogOptionsReset local optionDesc=GUIHelper:CreateTextLogWidget(nameID.."_textLog"..i,option.x+1,option.y+4,option1Desc.w,option1Desc.h,glEmptyGUIStyle,true,nil) --make mouse ignore description control optionDesc.updateSelf=function() end optionDesc:addParent(option) optionDesc.resultTexts={} optionDesc.color=15 GUIHelper:InsertUnparsedTextIntoTextGUIFrame(choiceData[z].optionTextStr,optionDesc) prevOption=option option.descGUI=optionDesc table.insert(optionsGUI,option) end end end frame.optionsGUI=optionsGUI return frame end function GUIHelper:CreateTextLogWithTitleInFoldableFrame(nameID,x,y,w,h,titleText,smallFontOnTextLog) local style=glBackgroundWithBorderGUIBlackStyle local frame=GUIHelper:CreateGUIFrame(nameID,x,y,w,h,style) frame.folded=false frame.titleText=titleText frame.titleSummary="" frame.controlsToReposition={} frame.repositionControlFunc=function(frame,hDiff,level) local level=level or 0 foreach(frame.controlsToReposition,function(control) Logger:Trace(level.."%REPOSITIONING:"..control.titleText,glMsgType.GUI) control.y=control.y-hDiff control:anchor(control.parent) --we have to reanchor control to not snap back to orig location if control.controlsToReposition then control:repositionControlFunc(hDiff,level+1) end end) end frame:Content(function(ref,x,y) print(ref.titleText.." "..frame.titleSummary,x+1,y+1,5) end) local textLogHackW=0 local textLog=GUIHelper:CreateTextLogWidget(nameID.."_textLog",x+1,y+2,w-2+textLogHackW,h-4,glEmptyGUIStyle,smallFontOnTextLog) textLog:addParent(frame) frame.textLog=textLog frame.SetNewHeight=function(frame,h) frame.h=h frame.textLog.h=h-12 end local button=GUIHelper:CreateButtonWidget(nameID.."_CloseOpenButton",x+w-16,y+1,15,9,glBackgroundWithBorderClickable2GUIStyle,base,"\\/") button:addParent(frame) local onCleanReleaseFunc=function(ref) local frame=ref.parent if frame then local folded =frame.folded if not folded then frame.origH=frame.h frame.textLog.origH=frame.textLog.h end frame.folded=not folded ref.text=(folded and "/\\" or "\\/") folded =frame.folded frame.textLog.h=(folded and 0 or frame.textLog.origH) local lastH=frame.h frame.h=(folded and 11 or frame.origH) local hDiff=lastH-frame.h frame:repositionControlFunc(hDiff) end end button.onCleanRelease=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref) onCleanReleaseFunc(ref) end frame.foldButton=button frame.ClickFoldButton = function(ref) ref.foldButton:onCleanRelease() end frame.RegisterControlToMoveOnFoldAction=function(ref,controlBelow) table.insert(ref.controlsToReposition,controlBelow) end return frame end function GUIHelper:BlinkControlForGivenConditionFunc(control,conditionFunc,delay, blink) AsyncQueueDrawHelper:AddToQueue( function(data) if data.conditionFunc then if data.conditionFunc() then GUIHelper:BlinkControlForGivenConditionFunc(control,data.conditionFunc,0.01, not blink) end end local ctrl=data.control if ctrl and not ctrl.isRemoved then ctrl.border=(data.blink and glGUIFrameStyleBlinkCard1 or glGUIFrameStyleBlinkCard2).border end end,{control=control, oldStyle=control.style, conditionFunc=conditionFunc, blink=blink},delay) end function GUIHelper:CreateTutorialDialog(onCleanReleaseFunc,text) if glTutorialDialog then glTutorialDialog:hide() glTutorialDialog:remove() end local funcToPass=function(ref) glTutorialDialog:hide() glTutorialDialog:remove() onCleanReleaseFunc(ref) end local longestLine=10 foreach(text, function(line) local l=#line longestLine=l>longestLine and l or longestLine end) --TODO: move to stringhelper --TODO: use output from print to calculate actual length of printed string - use code from main menu local offX=longestLine*6 offX=offX<240 and offX or 240 local w=offX local x=glScreenPixelWidth/2-offX/2 ---120 local offH=((#text)-2)*7 local h=29+offH local y=glScreenPixelHeight/2-30-offH/2 local dialog = self:CreateDialogWithOkButton("tutorialDialog",x,y,w,h,glTutorialDialogGUIStyle,false,1,funcToPass,text,-6) StateHelper.CleanPlayerMouseSelection() return dialog end function GUIHelper:CreateDialogWithOkButton(nameID,x,y,w,h,style,smallFont,backgroundColor, onCleanReleaseFunc,textOrTextArray,textHOffset) local base = GUIHelper:CreateGUIFrame(nameID,x,y,w,h,style) local textLog=GUIHelper:CreateTextLogWidget(nameID.."_textLog",base.x+1,base.y+1,base.w-2,base.h-12,glEmptyGUIStyle,smallFont,backgroundColor,textHOffset) textLog:addParent(base) if type(textOrTextArray)=="string" then textLog.drawText=textOrTextArray else textLog.resultTexts=textOrTextArray end base.textLog=textLog local button=GUIHelper:CreateButtonWidget(nameID.."_OkButton",base:getCenterX()-20,base.y+base.h-11,40,9,glGUIFrameStyleActiveOKCard,base,"OK") button:addParent(base) button.onCleanRelease=function(ref) GUIHelper.InteractableActiveControlBaseClickFunc(ref) onCleanReleaseFunc(ref) end return base end function GUIHelper:CreateTextLogWidget(nameID,x,y,w,h,style,smallFont,backgroundColor,textHOffset) local widget=GUIHelper:CreateGUIFrame(nameID,x,y,w,h,style) textHOffset = textHOffset or 0 widget.resultTexts={} widget.scroll=1 widget.smallFont=smallFont widget:Content(function(ref,x,y) if backgroundColor then rect(x+1,y+1,ref.w-3,ref.h-4,backgroundColor) end if ref.drawText then ref.resultTexts=GUIHelper:ParseStringToArrayOfStringsForGUISpace(ref.drawText,ref,smallFont,false) end if ref.resultTexts then local i=1 local n=#ref.resultTexts local color=ref.color or 15 foreach(ref.resultTexts, function(text) local sprite=nil if type(text)~="string" then local arr=text text=arr.text sprite=arr.spr end color=printPlus(text,ref.x+3+(sprite and 8 or 0),ref.y+1+i*7+textHOffset,color,false,1,smallFont) if sprite then spr(sprite,ref.x+3,ref.y+i*7+textHOffset) end i=i+1 end) end end) return widget end function GUIHelper.ChoiceContentFunction(ref,x,y) local text = ref.text rect(x,y,ref.w,ref.h,((ref.blink and glFrame60FramesCounter%20<10) and 6 or 0)) if not ref.parent.visible or text==nil then ref:visible(false) else if ref.alignToRight then x=ref.w-(ref.smallFont and 4 or 6)*string.len(text) end print(text,x+1,y+((ref.h>7 and not ref.mini) and 1 or 0),ref.color,ref.fixed,ref.scale and ref.scale or 1, ref.smallFont) end end function GUIHelper:PopulateTagsSelection(parentControl,tagsToInclude,maxTagsSelected,dontUsePoints) local i=0 local sortedTags={} maxTagsSelected=maxTagsSelected or 6 local tags=shallowcopy(glUnitTags) --add special tags that require manual %insert local sTag=deepcopy(glUnitTags.SUMMON) sTag.data.split[2]="U011" sTag.costValue=2 tags.SUMMON_U011=sTag sTag=deepcopy(glUnitTags.SPELLPWR) sTag.data.split[2]="UP" sTag.data.spellPWR=1 sTag.costValue=2 sTag.spr=492 tags.SPELLPWR_UP=sTag sTag=deepcopy(glUnitTags.SPELLPWR) sTag.data.split[2]="DOWN" sTag.data.spellPWR=1 sTag.costValue=2 sTag.spr=261 tags.SPELLPWR_DOWN=sTag --end foreach(tags,function(tag) if tag.costValue then local id=tag.costValue*100 while(sortedTags[id]) do id=id+1 end sortedTags[id]=tag end end) local tagsUnlocks={} foreach(sortedTags,function(tag) if tag.costValue and tag.costValue~=0 and (not tagsToInclude or (table.contains(tagsToInclude,tag.id))) then local tagUnlock=nil local unlocked=true Logger:Trace("CHECKING TAG:"..tag.name,glMsgType.INIT_BASE) local unlockStr="not unlocked" foreach(AchievementsHelper.unlocksData,function(data) if string.split(data.name," ")[1]==tag.name and string.find(data.name,"TAG") then unlocked=data.unlocked if not unlocked then unlockStr=data.req.." "..data.reqVal.." TIMES" end Logger:Debug("TAG:"..tag.name..(unlocked and " UNLOCKED" or " LOCKED"),glMsgType.INIT_BASE) end end) local tagButton=GUIHelper:CreateButtonWidget(tag.name.."_tagButton",parentControl.x+2+(i>10 and (parentControl.w-6)/2+1 or 0),parentControl.y+9+(i>10 and -99 or 0)+i*9, (parentControl.w-6)/2,9,glBackgroundWithBorderClickableGUIStyle,parentControl,(unlocked and (" "..tag.name.." ("..-tag.costValue..")") or unlockStr),nil,(unlocked and 15 or 3)) tagButton:addParent(parentControl) tagButton.unlocked=unlocked local tagFunc=function(ref,x,y) GUIHelper.ChoiceContentFunction(ref,x,y) if ref.unlocked then spr(tag.spr,x,y-1) end end tagButton:Content(tagFunc) tagButton.clicked=false tagButton.tagObj=tag tagButton.dontUsePoints=dontUsePoints tagButton.maxTagsSelected=maxTagsSelected tagButton.onCleanRelease=function(ref) if not ref.unlocked then return end ref.clicked=not ref.clicked local reverted=false local points=ref.dontUsePoints and {cur=99} or GameHelper.playerLeaderCard.stats.pointsToAllocate if ref.clicked then points.cur=points.cur-tag.costValue parentControl.tagsSelected=parentControl.tagsSelected+1 if points.cur<0 or parentControl.tagsSelected>6 then ref.clicked=false points.cur=points.cur+tag.costValue reverted=true parentControl.tagsSelected=parentControl.tagsSelected-1 end else points.cur=points.cur+tag.costValue parentControl.tagsSelected=parentControl.tagsSelected-1 if points.cur<0 then ref.clicked=true points.cur=points.cur-tag.costValue reverted=true parentControl.tagsSelected=parentControl.tagsSelected+1 end end if not reverted then GUIHelper.InteractableActiveControlBaseClickFunc(ref) end if ref.clicked then ref.border=glGUIFrameStyleActiveOKCard.border else ref.border=glBackgroundWithBorderClickableGUIStyle.border end end local tagFunc=function(ref) local tag=ref.tagObj if tag and ref.unlocked then table.insert(glGUIFrameMouseTooltip.textArray,{prefixSpr=tag.spr,text=tag:genNameAsStr(),color=14,smallFont=false}) local desc=tag:genDesc() --hack because of bug introduced with genDesc?? for n=0,(#desc) do local d=desc[n] if d then table.insert(glGUIFrameMouseTooltip.textArray,{text=d.str,color=d.c,smallFont=true}) end end UpdateMouse() end end tagButton.onHover=function(ref) if GameHelper.controlScheme<2 then tagFunc(ref) end end tagButton.onPress=function(ref) if GameHelper.controlScheme==2 then tagFunc(ref) end end foreach(GameHelper.playerLeaderCard.tags,function(playerTag) if playerTag.name==tag.name then tagButton.clicked=true tagButton.border=glGUIFrameStyleActiveOKCard.border end end) table.insert(parentControl.tagsGUI,tagButton) i=i+1 end end) end function GUIHelper.ShakeFrameControl(selCardGUI1st,offsetStrength,length,delayTime) if not selCardGUI1st then return end local shakeFunc shakeFunc=function(data) local fade = 0.95 local offset_x=2-math.random(4) local offset_y=2-math.random(4) offset_x=data.offset*offset_x offset_y=data.offset*offset_y data.cardGUI.x=data.origX+offset_x data.cardGUI.y=data.origY+offset_y data.offset=fade*data.offset data.length=data.length-0.02 if data.offset<0.05 or data.length<=0 then data.cardGUI.x=data.origX data.cardGUI.y=data.origY else AsyncQueueLogicHelper:AddToQueue(shakeFunc,{cardGUI=data.cardGUI, offset=data.offset,origX=data.origX,origY=data.origY,length=data.length},0.02) end end AsyncQueueLogicHelper:AddToQueue(shakeFunc,{cardGUI=selCardGUI1st, offset=offsetStrength,origX=selCardGUI1st.origX,origY=selCardGUI1st.origY,length=length},delayTime) end function GUIHelper:FlashControlBorderForTime(cardGUI,style,t) --TODO: LOOK HERE if cardGUI and not cardGUI.isFlashing then cardGUI.isFlashing=true local border=cardGUI.border cardGUI.border=glGUIFrameStyleActiveWarningCard.border AsyncQueueLogicHelper:AddToQueue(function(data) if cardGUI then cardGUI.border=data.border cardGUI.isFlashing=false end end,{border=border},t) end end function GUIHelper:ShowActionAIDoneToPlayer(card,targetCard,typeOfAction,cardAfterAction,targetCardAfterAction) local time=1-- AIHelper.aiTurnTimeOfNextAction-AIHelper.aiTurnTimeCur local startOffsetX=0 local frame=self:CreateGUIFrame("AIActionPreviewFrame",-90,glScreenPixelHeight/2-30,90,35,glBackgroundWithBorderGUIBlackStyle) local moveToX=0 local offY=8 local endX=50 local onHover=function(ref) ref.isHover=true frame.isHover=true GUIHelper.notUpdateAIActionEvents=true end local notOnHover=function(ref) ref.isHover=false frame.isHover=false end frame.onReleaseHover=notOnHover frame.onHover=onHover frame.timer=time frame.movePerFrame=15 frame.moveToX=moveToX frame.typeOfAction=typeOfAction --TODO: tie this to ai doing next move - can't do next move if this is visible!! frame:Content(function(ref,x,y) if ref.timer<=0 then return end local l=print(typeOfAction,-2000,-2000,11) print(typeOfAction,x+ref.w/2-l/2,y+1,11) for i=1,#ref.cards do local c=ref.cards[i] and ref.cards[i].cardGUI if c then local c1A=ref.actionCardsGUI[i] if c1A then local x1=c:getCenterX() local x2=c1A:getCenterX() local y1=(c.origY and c.origY or c.y)+(c.isPlayerCard and 0 or c.h) local y2=(c1A.origY and c1A.origY or c1A.y)+(c1A.isPlayerCard and c1A.h or 0) local canDraw=GUIHelper.AIActionFramesList[#GUIHelper.AIActionFramesList]==ref --it means that it is on top if canDraw and (not c1A.cardObj.isSpell) then table.insert(glFullScreenGameOverlayToDrawOn.pointCoordsAndColorToDrawLinesList,{x1=x1,y1=y1,x2=x2,y2=y2,c=14,w=3}) end end end end if typeOfAction=="DRAWS CARD" or typeOfAction=="NO CARDS LEFT" then table.insert(glFullScreenGameOverlayToDrawOn.pointCoordsAndColorToDrawLinesList,{x1=glEnemyToolbarCards:getCenterX(),y1=glEnemyToolbarCards.y+glEnemyToolbarCards.h,x2=frame:getCenterX(),y2=frame.y,c=14,w=3}) end end) local cards={card,targetCard} local oneCard=(not card) or (not targetCard) frame.cards=cards frame.actionCardsGUI={} for i=0,1 do local cObj=cards[i+1] if cObj or i==1 then local card = GUIHelper:CreateGUIFrame("AIActionPreviewFrame_card"..i,frame.x+2+(oneCard and 24 or i*48),frame.y+offY,39,25) card:addParent(frame) card.name="PreviewActionCard" card.isPlayerCard=cObj and cObj.isPlayerCard card.isHandCard=cObj and cObj.isHandCard card.isLeaderCard=cObj and cObj.isLeaderCard card.pos=i+1 card.origX=card.x card.origY=card.y card.cardObj=cObj card.reverseValues=true card.staticSimulatedCardObj=(i==0 and cardAfterAction or targetCardAfterAction) card:style(glGUIFrameStyleUnusableCard) if not cObj then if typeOfAction=="DRAWS CARD" then card:Content(function(ref,x,y) print("UNKNOWN",x+5,y+8,(GameHelper.cardGUIElemHoveredOver==ref and 15 or 4),false,1,true) end) else --TODO: look here move them to array like glmsgtype card:Content(function(ref,x,y) print("DMG TAKEN",x+2,y+8,6,false,1,true) end) end else card:Content(GUIHelper.BattlefieldCardDrawingFunction) end card.onReleaseHover=notOnHover card.onHover=function(ref) if GameHelper.controlScheme<2 then GUIHelper.controlHoveredOver=ref GameHelper.cardGUIElemHoveredOver=ref end onHover(ref) end frame.actionCardsGUI[i+1]=card end end foreach(frame.actionCardsGUI,function(cardGUI) cardGUI:visible(typeOfAction=="DRAWS CARD" or typeOfAction=="NO CARDS LEFT" or cardGUI.staticSimulatedCardObj~=nil) end) frame.updateTimer=function(ref) local f=ref local y,k=table.contains(GUIHelper.AIActionFramesList,ref) if f.timer<=0 then f:hide() if k then table.remove(GUIHelper.AIActionFramesList,k) end return else AsyncQueueLogicHelper:AddToQueue(function(data) f:updateTimer() end,{frame=frame},glFrameTimePerFrame) end local update=(not f.isHover) or not GUIHelper.notUpdateAIActionEvents AIHelper.stopUpdatingAI=not update if update then f.timer=f.timer-glFrameTimePerFrame local diff=(#GUIHelper.AIActionFramesList)-k local offset=frame.x+frame.movePerFrame if f.timer<0.4 then offset=frame.x-frame.movePerFrame frame.x=offset elseif diff>0 then local newX=frame.moveToX+90*diff if offset>newX then offset=newX end frame.x=offset elseif frame.moveToX~=frame.x then frame.x=offset end end end glFullScreenGameOverlayToDrawOn:allToFront() AsyncQueueLogicHelper:AddToQueue(function(data) frame:updateTimer() end,{frame=frame},glFrameTimePerFrame) table.insert(self.AIActionFramesList,frame) end function GUIHelper.BattlefieldCardDrawingFunction(ref,x,y) local cardObj=ref.simulatedCardObj and ref.simulatedCardObj or (ref.staticSimulatedCardObj and ref.staticSimulatedCardObj or ref.cardObj) if cardObj==nil or ref.cardObj==nil then rect(x,y,x+ref.w,y+ref.h,0) return end rect(x,y,13,15,0) print(cardObj.id,x+ref.w-25,y+1,(GameHelper.cardGUIElemHoveredOver==ref and 15 or 4)) y=y+1 local revVals=ref.reverseValues local trueStats=ref.cardObj.stats local cardStats=cardObj.stats if cardObj.isSpell then rect(x+0,y+14,37,8,9) spr(262,x+30,y+14,0) local val=cardStats.spellPower.cur print(val,x+1,y+15,2) else local hasArmor=trueStats.armor.cur>0 local attackChange= trueStats.attack.cur-cardStats.attack.cur or nil if attackChange and attackChange~=0 and glPulseStatusForEvery30thFrame then attackChange=attackChange*(revVals and -1 or 1) rect(x+0,y+14,12+(hasArmor and 0 or 6),8,0) print((attackChange>0 and "-" or "+")..math.abs(attackChange),x+1,y+15,attackChange>0 and 6 or 11) else rect(x+0,y+14,12+(hasArmor and 0 or 6),8,14) spr(256,x+4+(hasArmor and 0 or 6),y+14,0) local val=cardStats.attack.cur print(val,x+1,y+15,2) end local dmgChange= trueStats.armor.cur-cardStats.armor.cur or nil val=cardStats.armor.cur if hasArmor then if dmgChange and dmgChange~=0 and glPulseStatusForEvery30thFrame then dmgChange=dmgChange*(revVals and -1 or 1) rect(x+25,y+14,12,8,0) print((dmgChange>0 and "-" or "+")..math.abs(dmgChange),x+26,y+15,dmgChange>0 and 6 or 11) else rect(x+25,y+14,12,8,3) spr(258,x+30,y+14,0) val=cardStats.armor.cur print(val,x+26,y+15,15) end end dmgChange= trueStats.hp.cur-cardStats.hp.cur or dmgChange x=x+1 if dmgChange and dmgChange~=0 and glPulseStatusForEvery30thFrame then dmgChange=dmgChange*(revVals and -1 or 1) rect(x+11+(hasArmor and 0 or 6),y+14,13+(hasArmor and 0 or 6),8,0) print((dmgChange>0 and "-" or "+")..math.abs(dmgChange),x+13+(hasArmor and 0 or 6),y+15,dmgChange>0 and 6 or 11) else local hpPercent=cardStats.hp:percent() rect(x+11+(hasArmor and 0 or 6),y+14,13+(hasArmor and 0 or 6),8,1) spr((hpPercent<=0 and 26 or(hpPercent<0.51 and 10 or (cardStats.hp:belowMax() and 11 or 257))),x+16+(hasArmor and 0 or 6)+(hasArmor and 0 or 5),y+14,0) val=cardStats.hp.cur print(val,x+12+(hasArmor and 0 or 6),y+15,15) end end spr(cardObj.sprite,ref.x,ref.y,0,1,0,0,2,2) x=x+12 y=y-18 if cardObj.isSpell then for i=0,#cardObj.tags-1 do spr(cardObj.tags[i+1].spr,x+17-i*8,y+24) end else for i=0,#cardObj.tags-1 do spr(cardObj.tags[i+1].spr,x+i*8,y+24) end end if (not cardObj.isSpell) and cardStats.hp.cur<=0 then rect(ref.x,ref.y,14,16,0) spr(272,ref.x+4,ref.y+5,6) end ref.simulatedCardObj=nil end --TODO: look into consolidating drawingfunctions to save space function GUIHelper.ListCardDrawingFunction(ref,x,y) local cardObj=ref.cardObj if not cardObj then return end local stats=cardObj.stats if not stats then return end rect(x,y,15,8,13) spr(259,x+7,y,0) local val=stats.manaCost.cur print(val,x+1,y+1,2) print(cardObj.id,x+16,y+1,15) if cardObj.isSpell then x=x+40 rect(x,y,39,8,9) spr(262,x+31,y,0) val=stats.spellPower.cur print(val,x+1,y+1,2) else local hasArmor=stats.armor.cur>0 x=x+40 rect(x,y,13+(hasArmor and 0 or 7),8,14) spr(256,x+5+(hasArmor and 0 or 6),y,0) val=stats.attack.cur print(val,x+1,y+1,2) rect(x+13+(hasArmor and 0 or 6),y,13+7,8,1) spr(257,x+18+(hasArmor and 0 or 13),y,0) val=stats.hp.cur print(val,x+14+(hasArmor and 0 or 6),y+1,15) if hasArmor then rect(x+26,y,13,8,3) spr(258,x+32,y,0) val=stats.armor.cur print(val,x+27,y+1,15) end end x=x+40 print(cardObj.isSpell and "SPELL" or "UNIT",x,y+1,15,false,1,cardObj.isSpell) x=x+24 i=0 foreach(cardObj.tags,function(tag) spr(tag.spr,x+i*8,y) i=i+1 end) rect(x+24,y,8,10,0) print(cardObj.rarity,x+25,y+1,cardObj.rarity=="N" and 15 or (cardObj.rarity=="R" and 13 or 9)) if ref.toDelete then x=ref.x y=ref.y local y1=y+ref.h/2 line(x-1,y1-1,x+ref.w+1,y1-1,6) line(x-1,y1,x+ref.w+1,y1,6) line(x-1,y1+1,x+ref.w+1,y1+1,6) end end function GUIHelper.BucketCardDrawingFunction(ref,x,y) local cardObj=ref.cardObj if not cardObj then return end local stats=cardObj.stats if not stats then return end rect(x,y,16,16,0) spr(cardObj.sprite,x,y,0,1,0,0,2,2) x=x+16 rect(x,y,14,8,13) spr(259,x+6,y,0) local val=stats.manaCost.cur print(val,x+1,y+1,2) print(cardObj.id,x+15,y+1,15) y=y-6 if cardObj.isSpell then rect(x,y+14,39,8,9) spr(262,x+32,y+14,0) val=stats.spellPower.cur print(val,x+1,y+15,2) else local hasArmor = stats.armor.cur>0 rect(x,y+14,13+(hasArmor and 0 or 7),8,14) spr(256,x+5+(hasArmor and 0 or 6),y+14,0) val=stats.attack.cur print(val,x+1,y+15,2) rect(x+13+(hasArmor and 0 or 6),y+14,13+(hasArmor and 0 or 8),8,1) spr(257,x+18+(hasArmor and 0 or 13),y+14,0) val=stats.hp.cur print(val,x+14+(hasArmor and 0 or 6),y+15,15) if hasArmor then rect(x+26,y+14,13,8,3) spr(258,x+32,y+14,0) val=stats.armor.cur print(val,x+27,y+15,15) end end y=y+22 print(cardObj.isSpell and "SPELL" or "UNIT",ref.x+2,y+1,15,false,1,cardObj.isSpell) x=ref.x+ref.w-32 i=0 foreach(cardObj.tags,function(tag) spr(tag.spr,x+i*8,y) i=i+1 end) rect(x+24,y,8,10,0) print(cardObj.rarity,x+25,y+1,cardObj.rarity=="N" and 15 or (cardObj.rarity=="R" and 13 or 9)) end function GUIHelper.HandCardDrawingFunction(ref,x,y) local cardObj=ref.cardObj if cardObj==nil then if ref.isFindCard then print("NO CARD",ref.x+2,ref.y+2,6) rect(x,y,ref.w,14,2) print("NO CARD",ref.x+2,ref.y+2,6) end return end local isPlayer=cardObj.isPlayerCard local playerLeaderCard = GameHelper.playerLeaderCard rect(x,y,15,15,0) x=x+3 y=y+1 print(cardObj.id,x+13,y,15) if cardObj.stats.manaCost.cur and playerLeaderCard and playerLeaderCard.stats then rect(x+12,y+6,24,8,13) local canUse=cardObj.stats.manaCost.cur<=playerLeaderCard.stats.manaCount.cur spr(canUse and 12 or 259,x+ref.w-13,y+6,0) local val=cardObj.stats.manaCost.cur print(val,x+13,y+7,2) end x=x-3 if cardObj.isSpell then rect(x+0,y+14,39,8,9) spr(262,x+ref.w-10,y+14,0) local modVal=GameHelper:FindAmountOfSpellPowerOnBattlefield(isPlayer) val=cardObj.stats.spellPower.cur print(val,x+1,y+15,0) --TODO: add more modular way to determine what not to buff with spellpwr if modVal~=0 and cardObj.id~="S032" and cardObj.id~="S033" then print((modVal>0 and "+" or "")..modVal,x+7,y+15,(modVal>0 and 5 or 6)) end else local hasArmor=cardObj.stats.armor.cur>0 rect(x+0,y+14,13+(hasArmor and 0 or 7),8,14) spr(256,x+5+(hasArmor and 0 or 6),y+14,0) val=cardObj.stats.attack.cur print(val,x+1,y+15,2) rect(x+13+(hasArmor and 0 or 6),y+14,13+(hasArmor and 0 or 8),8,1) spr(257,x+18+(hasArmor and 0 or 7)+(hasArmor and 0 or 6),y+14,0) val=cardObj.stats.hp.cur print(cardObj.stats.hp.cur,x+14+(hasArmor and 0 or 6),y+15,15) if hasArmor then rect(x+26,y+14,13,8,3) spr(258,x+32,y+14,0) val=cardObj.stats.armor.cur print(cardObj.stats.armor.cur,x+27,y+15,15) end end y=y+4 i=0 foreach(cardObj.tags,function(tag) spr(tag.spr,x,y+19+i*8) local name=tag:genName(cardObj) if string.len(name[1])>7 then y=y+8 print(name[1],x,y+20+i*8,14,false,1,(string.len(name[1])>4)) else print(name[1],x+9,y+20+i*8,14,false,1,(string.len(name[1])>4)) end i=i+1 if name[2] then local split=(name[2] or "")..(name[3] or "") print(split,x,y+20+i*8,14,false,1,(string.len(split)>4)) i=i+1 end end) spr(cardObj.sprite,ref.x,ref.y,0,1,0,0,2,2) if ref.drawX then line(ref.x,ref.y,ref.x+ref.w,ref.y+ref.h+1,6) line(ref.x+1,ref.y,ref.x+ref.w,ref.y+ref.h-1,6) line(ref.x+ref.w-1,ref.y,ref.x,ref.y+ref.h,6) line(ref.x+ref.w,ref.y,ref.x+1,ref.y+ref.h,6) end if cardObj.isFatiqueCard then x=ref.x y=ref.y rect(x,y,ref.w,ref.h,6) rect(x+0,y+1,ref.w,8,1) print("NO CARDS",x+4,y+2,15,false,1,true) y=y-9 rect(x+0,y+17,ref.w,9,0) val=cardObj.stats.attack.cur spr(272,x+8+(val>9 and 6 or 0),y+18,0) print(val,x+2,y+19,6) print("Deals DMG \nto HP\nequal to \namount of\nVOID cards \ndrawn",ref.x+2,ref.y+20,15,false,1,true) end end function GUIHelper.LeaderCardDrawingFunction(ref,x,y) rect(x,y,16,18,0) local cardObj=ref.simulatedCardObj and ref.simulatedCardObj or ref.cardObj if cardObj==nil then return end local isEnemy=(not cardObj.isPlayerCard) spr(cardObj.sprite,x,y-1,0,1,1,0,2,2) print(cardObj.id,x+17,y+1,15) x=x-4 y=y-6 local trueStats=ref.cardObj.stats local cardStats=cardObj.stats local hasArmor=cardObj.stats.armor.cur>0 local attackChange= ref.simulatedCardObj and trueStats.attack.cur-cardStats.attack.cur or nil if attackChange and attackChange~=0 and glPulseStatusForEvery30thFrame then rect(x+20,y+14,12+(hasArmor and 0 or 7),8+(hasArmor and 0 or 6),0) print((attackChange>0 and "-" or "+")..math.abs(attackChange),x+21+(hasArmor and 0 or 6),y+15,attackChange>0 and 6 or 11) else rect(x+20,y+14,12+(hasArmor and 0 or 7),8,14) spr(256,x+24+(hasArmor and 0 or 6),y+14,0) local val=cardObj.stats.attack.cur print(val,x+21,y+15,2) end local dmgChange= ref.simulatedCardObj and trueStats.armor.cur-cardStats.armor.cur or nil if hasArmor then x=x+2 if dmgChange and dmgChange~=0 and glPulseStatusForEvery30thFrame then rect(x+44,y+14,12,8,0) print((dmgChange>0 and "-" or "+")..math.abs(dmgChange),x+45,y+15,dmgChange>0 and 6 or 11) else rect(x+44,y+14,12,8,3) spr(258,x+49,y+14,0) val=cardObj.stats.armor.cur print(val,x+45,y+15,15) end x=x-2 end dmgChange= ref.simulatedCardObj and trueStats.hp.cur-cardStats.hp.cur or nil if dmgChange and dmgChange~=0 and glPulseStatusForEvery30thFrame then rect(x+32+(hasArmor and 0 or 6),y+14,12+(hasArmor and 0 or 6),8,0) print((dmgChange>0 and "-" or "+")..math.abs(dmgChange),x+33+(hasArmor and 0 or 6)+(hasArmor and 0 or 6),y+15,dmgChange>0 and 6 or 11) else local hpPercent=cardObj.stats.hp:percent() val=math.floor(cardObj.stats.hp.cur) rect(x+32+(hasArmor and 0 or 6),y+14,14+(hasArmor and 0 or 6),8,1) spr((hpPercent<=0 and 26 or(hpPercent<0.51 and 10 or (cardObj.stats.hp:belowMax() and 11 or 257))),x+38+(hasArmor and 0 or 7)+(hasArmor and 0 or 5),y+14,0) print(val,x+33+(hasArmor and 0 or 6),y+15,15) end y=y-2 for i=0,5 do local tag=cardObj.tags[i+1] if tag then spr(tag.spr,x+58+(i%3)*8,y+8+8*math.floor(i/3)) end end ref.simulatedCardObj=nil end function GUIHelper.TextLogContentFunction(ref, x, y) if ref.textArray then local n=#ref.textArray local h=2+8*n local w=ref.w local smallFontN=0 --for line wrap (on each line!) if msg.len exists for i=1,n do local msg=ref.textArray[i] msg.spl={} local l=msg.len if l then local t=msg.text local j=1 if t and string.len(t)>l then local split=string.split(t," ") local startsWithSpace=t:sub(1,1)==" " local curLine="" local inserted=0 foreach(split, function(word) if string.len(curLine..word)>l then table.insert(msg.spl,curLine) curLine=word h=h+8 inserted=inserted+1 else curLine=curLine..((curLine~="" or startsWithSpace) and " " or "")..word end end) if curLine~="" then table.insert(msg.spl,curLine) end end end end for i=1,n do local msg=ref.textArray[i] if msg then if (#msg.spl)>0 then local l=msg.len local j=0 foreach(msg.spl,function(splitLine) local x1=0 local y1=0 if msg.prefixSpr then x1=9 y1=1 spr(msg.prefixSpr,x+1, y+(i-1)*8+8*j-smallFontN) end local cl=print(splitLine, x1+x+1, y+y1+1+(i-1)*8+8*j-smallFontN,msg.color,msg.fixed,msg.scale and msg.scale or 1,msg.smallFont) w=math.max(w,cl+5) if msg.smallFont then smallFontN=smallFontN+2 end j=j+1 end) y=y+8*(#msg.spl-1) else local x1=0 local y1=0 if msg.prefixSpr then x1=9 y1=1 spr(msg.prefixSpr,x+1, y+(i-1)*8-smallFontN) end local cl=print(msg.text, x1+x+1, y+y1+1+(i-1)*8-smallFontN,msg.color,msg.fixed,msg.scale and msg.scale or 1,msg.smallFont) w=math.max(w,cl+5) if msg.smallFont then smallFontN=smallFontN+2 end end end end ref.w=w-2 ref.h=h-smallFontN+1 end end function GUIHelper.ShowEndGameSummaryScreen() GameHelper.ShowedEndGameSummary=true if not glGUIFrameEndScreenBackground then GUICreator:CreateGameEndScreen() end glGUIFrameEndScreenBackground:show() local textLog=glGUIFrameEndScreenTextLog local total=0 local mult=1 local score=0 local unlocks=0 local textLog=glGUIFrameEndScreenUnlocksSummary.textLog GameHelper.numOfPlayingGameMode=GameHelper.numOfPlayingGameMode+1 if GameHelper.currentPlayerLives>0 then GameHelper.numOfWinningGameMode=GameHelper.numOfWinningGameMode+1 end if (#AchievementsHelper.closestUnlocksData)> 0 then local descTable={} foreach(AchievementsHelper.closestUnlocksData,function(data) if data then if (data.req=="PLAY" and GameHelper.numOfPlayingGameMode or GameHelper.numOfWinningGameMode)>=data.reqVal then local str="^11Unlocked: "..data.name table.insert(descTable,str) GUIHelper:InsertUnparsedTextIntoTextGUIFrame(str,textLog) table.insert(descTable,data.desc) foreach(data.desc,function(desc) table.insert(descTable,desc) GUIHelper:InsertUnparsedTextIntoTextGUIFrame("^15"..desc,textLog) end) unlocks=unlocks+1 Logger:Debug("unlocked:"..data.name,glMsgType.GAME_LOGIC) end end end) if unlocks==0 then glGUIFrameEndScreenUnlocksSummary:hide() elseif unlocks>1 then glGUIFrameEndScreenUnlocksSummary:SetNewHeight(15+20*unlocks) end glGUIFrameEndScreenUnlocksSummary.titleSummary="("..unlocks..")" local unlockFunc=function(ref) glPlayerUnlocksDialog:hide() glPlayerUnlocksDialog:remove() end end local textLog=glGUIFrameEndScreenGeneralScoreSummary.textLog local genScore=0 if GameHelper.currentPlayerLives<=0 then GUIHelper:InsertUnparsedTextIntoTextGUIFrame("You've lost this run: 0",textLog) else genScore=genScore+ScoreHelper.gameWonValue GUIHelper:InsertUnparsedTextIntoTextGUIFrame("You've won this run: "..ScoreHelper.gameWonValue,textLog) end if GameHelper.lostPlayerLives>0 then mult=math.max(1,ScoreHelper.notLosingLifeMultValue-GameHelper.lostPlayerLives*ScoreHelper.losingLifeMultValue) GUIHelper:InsertUnparsedTextIntoTextGUIFrame("You've lost "..GameHelper.lostPlayerLives.." lives: (TOTAL x "..mult..")",textLog) else mult=ScoreHelper.notLosingLifeMultValue GUIHelper:InsertUnparsedTextIntoTextGUIFrame("You've didn't lost any lives: (TOTAL x "..mult..")",textLog) end score=GameHelper.gamesWon*ScoreHelper.matchWonValue genScore=genScore+score total=total+genScore GUIHelper:InsertUnparsedTextIntoTextGUIFrame("You've won "..GameHelper.gamesWon.." matches: "..score.." ("..GameHelper.gamesWon.."x"..ScoreHelper.matchWonValue..")",textLog) glGUIFrameEndScreenGeneralScoreSummary.titleSummary=genScore local textLog=glGUIFrameEndScreenUnitsScoreSummary.textLog local unitScore=0 score=ScoreHelper.turnSurvivedValue*ScoreHelper.turnSurvivedScore unitScore=unitScore+score GUIHelper:InsertUnparsedTextIntoTextGUIFrame("You've survived "..ScoreHelper.turnSurvivedScore.." turns in total: "..score.." ("..ScoreHelper.turnSurvivedScore.."x"..ScoreHelper.turnSurvivedValue..")",textLog) score=ScoreHelper.unitDiedValue*ScoreHelper.unitDiedScore unitScore=unitScore+score GUIHelper:InsertUnparsedTextIntoTextGUIFrame(ScoreHelper.unitDiedScore.." units died in total: "..score.." ("..ScoreHelper.unitDiedScore.."x"..ScoreHelper.unitDiedValue..")",textLog) score=ScoreHelper.unitKilledValue*ScoreHelper.unitKilledScore unitScore=unitScore+score GUIHelper:InsertUnparsedTextIntoTextGUIFrame(ScoreHelper.unitKilledScore.." units killed in total: "..score.." ("..ScoreHelper.unitKilledScore.."x"..ScoreHelper.unitKilledValue..")",textLog) score=ScoreHelper.leadersKilledValue*ScoreHelper.leadersKilledScore unitScore=unitScore+score GUIHelper:InsertUnparsedTextIntoTextGUIFrame(ScoreHelper.leadersKilledScore.." leaders killed in total: "..score.." ("..ScoreHelper.leadersKilledValue.."x"..ScoreHelper.leadersKilledScore..")",textLog) if ScoreHelper.receivedDamageToLeaderScore==0 then unitScore=unitScore+1500 GUIHelper:InsertUnparsedTextIntoTextGUIFrame("Your leader got 0 damage in total: "..score.." (1500)",textLog) else score=ScoreHelper.receivedDamageToLeaderValue*ScoreHelper.receivedDamageToLeaderScore unitScore=unitScore+score GUIHelper:InsertUnparsedTextIntoTextGUIFrame("Your leader got "..ScoreHelper.receivedDamageToLeaderScore.." damage in total: "..score.." ("..ScoreHelper.receivedDamageToLeaderScore.."x"..ScoreHelper.receivedDamageToLeaderValue..")",textLog) end score=ScoreHelper.dealtDamageValue*ScoreHelper.dealtDamageScore unitScore=unitScore+score GUIHelper:InsertUnparsedTextIntoTextGUIFrame(ScoreHelper.dealtDamageScore.." DMG was dealt in total: "..score.." ("..ScoreHelper.dealtDamageScore.."x"..ScoreHelper.dealtDamageValue..")",textLog) glGUIFrameEndScreenUnitsScoreSummary.titleSummary=total unitScore=unitScore total=total+unitScore local totalMult=math.floor(math.round(total*mult,0)) GameHelper.highestGameScore = totalMult>GameHelper.highestGameScore and totalMult or GameHelper.highestGameScore glGUIFrameEndScreenUnitsScoreSummary.titleSummary=unitScore local textLog=glGUIFrameEndScreenTotalScoreSummary.textLog GUIHelper:InsertUnparsedTextIntoTextGUIFrame("Your total score is: "..totalMult.." ("..total.."x"..mult..")",textLog) GUIHelper:InsertUnparsedTextIntoTextGUIFrame("Highest score ever: "..GameHelper.highestGameScore,textLog) GUIHelper:InsertUnparsedTextIntoTextGUIFrame("^13Game mode won: "..GameHelper.numOfWinningGameMode.." times (played: "..GameHelper.numOfPlayingGameMode.." times)",textLog) glGUIFrameEndScreenTotalScoreSummary.titleSummary=totalMult pmem(255,GameHelper.highestGameScore) pmem(254,GameHelper.numOfWinningGameMode) pmem(253,GameHelper.numOfPlayingGameMode) end function GUIHelper:DrawDamageIndicator(cardAttacked,cardAttacking,dmg,dmgType,delayForFX) self:DrawChangeIndicator(cardAttacked,dmgType,-dmg,delayForFX) end function GUIHelper:DrawChangeIndicator(cardAttacked,statType,val,delayForFX) if not cardAttacked then return end local x1=cardAttacked:getCenterX() local y1=cardAttacked:getDownY() local c1=14 local c2=6 local posC=11 y1=y1+(y1>(glScreenPixelHeight/2) and -18 or 2) if statType then if statType=="ARMOR" then x1=x1+5 c1=3 c2=6 posC=5 elseif statType=="HP" then x1=x1-2 c1=1 c2=6 elseif statType=="ATK" then x1=x1-18 end end local x2=glScreenPixelWidth/2 local y2=(y1>(glScreenPixelHeight/2)) and 10 or (glScreenPixelHeight-10) local x3=x2-x1 local y3=y2-y1 local n=45+10*(3-GameHelper.animationSpeed) local vAbs=math.abs(val) for i=0,n do local x4=x1+(x3/n*(i*2/n)) local y4=y1+(y3/n*(i*2/n)) local z=0.2+i/50 local quarterN=n/4 local drawBigger=(i>(n/quarterN)) and (i<(n-quarterN)) AsyncQueueDrawHelper:AddToQueue(function(data) rect(x4,y4,13+(vAbs>9 and 7 or 0),8,c1) print((val>0 and "+" or "")..val,x4+1,y4+1,((val>0 and posC or c2)),drawBigger and 2 or 1) end,{},delayForFX+z) end end -- TICUARE ticuare = {name = "ticuare", elements = {}, z = 1, hz = nil} ticuare.__index = ticuare ticuare.me = {nothing=0,click=1,noclick=2,none=3} -- Private local ticuareMt = {__index = ticuare} local function inArea(mx, my, x, y, w, h) return mx > x and mx < x+w and my > y and my < y+h end local function mergeTables(t1, t2, overwrite) for k,v in pairs(t2) do if type(v) == "table" then if type(t1[k] or false) == "table" then mergeTables(t1[k] or {}, t2[k] or {}, overwrite) else if not t1[k] or overwrite then t1[k] = v end end else if not t1[k] or overwrite then t1[k] = v end end end return t1 end -- pallete switch local function pal(c0,c1) if(c0==nil and c1==nil)then for i=0,15 do poke4(0x3FF0*2+i,i)end else poke4(0x3FF0*2+c0,c1)end end function ticuare.lerp(a, b, k) if a == b then return a else if math.abs(a-b) < 0.005 then return b else return a * (1-k) + b * k end end end local function copyTable(object) local lookup_table = {} local function _copy(object) if type(object) ~= "table" then return object elseif lookup_table[object] then return lookup_table[object] end local new_table = {} lookup_table[object] = new_table for i, v in pairs(object) do new_table[_copy(i)] = _copy(v) end return setmetatable(new_table, getmetatable(object)) end return _copy(object) end local function checkColors(hold, hover, one, two, three) if hold then return one elseif hover then return two else return three end end -- Public methods function ticuare.print(text,x,y,color,fixed,scale) -- string; x,y position; color; line height; fixed letters width fixed = fixed or false scale = scale or 1 local _, lines_count = text:gsub("\n","") local width, height = 0, 0 if color then width, height = print(text,x,y,color,fixed,scale), (6+lines_count) *scale *(lines_count+1) end return width, height end function ticuare.font(text,x,y,colors,key,space_w,space_h,fixed,scale) -- string; x,y position; color/-s; line height; transparent color; space width key = key or -1 space_w = space_w or 8 space_h = space_h or 8 fixed = fixed or false scale = scale or 1 local _, lines_count = text:gsub("\n","") if type(key)=="table" and type(key[1]) == "table" then for si, sc in ipairs(key[1]) do if type(colors)=="table" then pal(sc,colors[si]) else pal(sc,colors) end end key=key[2] end local width if colors then width = font(text,x,y,key,space_w,space_h,fixed,scale) end pal() return width, (space_h+lines_count)*scale*(1+lines_count) end function ticuare.element(element_type, element_obj) if not element_obj then element_obj = element_type element_type = "element" end local ticuareObj = element_obj setmetatable(ticuareObj, ticuare) ticuareObj.hover, ticuareObj.click = false, false ticuareObj.activity = element_obj.activity or true ticuareObj.drag = element_obj.drag or {activity = false} ticuareObj.align = element_obj.align or {x=0,y=0} ticuareObj.visibility = element_obj.visibility or true if ticuareObj.content then if not ticuareObj.content.scroll then ticuareObj.content.scroll = {x = 0, y = 0} end ticuareObj.content.w, ticuareObj.content.h = ticuareObj.content.w or ticuareObj.w, ticuareObj.content.h or ticuareObj.h end ticuareObj.type, ticuareObj.z = element_type, ticuare.z ticuare.z = ticuare.z + 1 ticuare.hz = ticuare.z --index stuff table.insert(ticuare.elements, ticuareObj) return ticuareObj end function ticuare.Element(f) return ticuare.element("element", f) end function ticuare.Style(f) return f end function ticuare.Group() local t = {type = "group", elements = {}} setmetatable(t, ticuare) return t end function ticuare:updateSelf(args) if args.mouse_x and args.mouse_y and args.event then mouse_x = args.mouse_x mouse_y = args.mouse_y mouse_press = args.press mouse_event = args.event local mouse_holding, mouse_over, element_in_focus, hovered, held, align_x, align_y local me, tempX, tempY = ticuare.me, self.x-(self.align.x==1 and self.w*.5 or (self.align.x==2 and self.w or 0)), self.y-(self.align.y==1 and self.h*.5-1 or (self.align.y==2 and self.h-1 or 0)) mouse_holding = mouse_event ~= me.none and mouse_press or false mouse_over = inArea(mouse_x, mouse_y, tempX, tempY, self.w, self.h) element_in_focus = mouse_event ~= me.none and mouse_over or false hovered, held = self.hover, self.hold self.hover = element_in_focus or (self.drag.active and ticuare.draging_obj and ticuare.draging_obj.obj == self) self.hold = ((mouse_event == me.click and element_in_focus) and true) or (mouse_holding and self.hold) or ((element_in_focus and mouse_event ~= me.noclick and self.hold)) if mouse_event == me.click and element_in_focus and self.onClick then --clicked self.onClick(self) elseif (mouse_event == me.noclick and element_in_focus and held) and self.onCleanRelease then self.onCleanRelease(self) elseif ((mouse_event == me.noclick and element_in_focus and held) or (self.hold and not element_in_focus)) and self.onRelease then --released (or mouse has left element, still holding temporarly) self.onRelease(self) elseif self.hold and self.onPress then --holding self.onPress(self) elseif not hovered and self.hover and self.onStartHover then --started hovering self.onStartHover(self) elseif self.hover and self.onHover then --hovering self.onHover(self) elseif hovered and not self.hover and self.onReleaseHover then --released hover self.onReleaseHover(self) end if self.hold and (not element_in_focus or self.drag.active) and not ticuare.draging_obj then self.hold = self.drag.active ticuare.draging_obj = {obj = self, d = {x = tempX-mouse_x, y = tempY-mouse_y}} -- save what and where is element holded elseif not self.hold and element_in_focus and (ticuare.draging_obj and ticuare.draging_obj.obj == self) then self.hold = true ticuare.draging_obj = nil end -- DRAGGING if ticuare.draging_obj and ticuare.draging_obj.obj == self and self.drag.active then self.x = (not self.drag.fixed or not self.drag.fixed.x) and mouse_x + ticuare.draging_obj.d.x or self.x self.y = (not self.drag.fixed or not self.drag.fixed.y) and mouse_y + ticuare.draging_obj.d.y or self.y local bounds = self.drag.bounds if bounds then if bounds.x then self.x = (bounds.x[1] and self.x < bounds.x[1]) and bounds.x[1] or self.x self.x = (bounds.x[2] and self.x > bounds.x[2]) and bounds.x[2] or self.x end if bounds.y then self.y = (bounds.y[1] and self.y < bounds.y[1]) and bounds.y[1] or self.y self.y = (bounds.y[2] and self.y > bounds.y[2]) and bounds.y[2] or self.y end end if self.track then self:anchor(self.track.ref) end end return element_in_focus elseif args.focused_element and args.event then local me, holding, over, element_in_focus, hovered, held = ticuare.me holding = args.event ~= me.none and args.press or false over = self == args.focused_element element_in_focus = args.event ~= me.none and over or false hovered, held = self.hover, self.hold self.hover = element_in_focus self.hold = ((args.event == me.click and element_in_focus) and true) or (holding and self.hold) or ((element_in_focus and args.event ~= me.noclick and self.hold)) if args.event == me.click and element_in_focus and self.onClick then --clicked self.onClick(self) elseif (args.event == me.noclick and element_in_focus and held) and self.onCleanRelease then self.onCleanRelease(self) elseif ((args.event == me.noclick and element_in_focus and held) or (self.hold and not element_in_focus)) and self.onRelease then --released (or mouse has left element, still holding temporarly) self.onRelease(self) elseif self.hold and self.onPress then --holding self.onPress(self) elseif not hovered and self.hover and self.onStartHover then --started hovering self.onStartHover(self) elseif self.hover and self.onHover then --hovering self.onHover(self) elseif hovered and not self.hover and self.onReleaseHover then --released hover self.onReleaseHover(self) end return element_in_focus else Logger:Error("updateSelf error in arguments!",glMsgType.GUI) Logger:Error(args,glMsgType.GUI) end end function ticuare:updateTrack() local bounds, track = self.drag.bounds, self.track if track then self.x, self.y = track.ref.x + track.d.x, track.ref.y + track.d.y if bounds and bounds.relative then if bounds.x then bounds.x[1] = track.ref.x + track.b.x[1] or nil bounds.x[2] = track.ref.x + track.b.x[2] or nil end if bounds.y then bounds.y[1] = track.ref.y + track.b.y[1] or nil bounds.y[2] = track.ref.y + track.b.y[2] or nil end end end end function ticuare:drawSelf () if self.visibility then local color, shadow_color, border_color, text_shadow_color, text_color, text_shadow, text_colors, sprite, tempX, tempY, text_width, text_height, text_x, text_y, border_colors, sprite_offset, text_offset, text_shadow_offset, shadow_offset, border_width, border_key, border_sprites, tile, dbl_border_width, text_align local shadow, border, text, icon, tiled, colors = self.shadow, self.border, self.text, self.icon, self.tiled, self.colors tempX = self.x-(self.align.x==1 and self.w*.5-1 or (self.align.x==2 and self.w-1 or 0)) tempY = self.y-(self.align.y==1 and self.h*.5-1 or (self.align.y==2 and self.h-1 or 0)) if shadow and shadow.colors then shadow.offset = shadow.offset or {x=1,y=1} shadow_color = checkColors(self.hold,self.hover, shadow.colors[3], shadow.colors[2], shadow.colors[1]) if shadow_color then rect(tempX+shadow.offset.x, tempY+shadow.offset.y,self.w, self.h, shadow_color) end end if colors then color = checkColors(self.hold,self.hover,colors[3],colors[2],colors[1]) if color then rect(tempX, tempY, self.w, self.h, color) end end border_width = border and (border.width) or 0 dbl_border_width = 2*border_width if tiled then tiled.scale = tiled.scale or 1 tiled.key = tiled.key or -1 tiled.flip = tiled.flip or 0 tiled.rotate = tiled.rotate or 0 tiled.w = tiled.w or 1 tiled.h = tiled.h or 1 tile = checkColors(self.hold,self.hover,tiled.sprites[3],tiled.sprites[2],tiled.sprites[1]) if tile then clip(tempX+border_width, tempY+border_width, self.w-dbl_border_width, self.h-dbl_border_width) for x=0,self.w+(8*tiled.w)*tiled.scale,(8*tiled.w)*tiled.scale do for y=0,self.h+(8*tiled.h)*tiled.scale,(8*tiled.h)*tiled.scale do spr(tile,tempX+x+border_width,tempY+y+border_width,tiled.key, tiled.scale, tiled.flip, tiled.rotate, tiled.w, tiled.h) end end clip() end end -- drawing element content if self.content and self.drawContent then if self.content.wrap and clip then clip(tempX+border_width, tempY+border_width, self.w-dbl_border_width, self.h-dbl_border_width) end --TODO: make true visible/notvisible if self.y<2000 then self:renderContent() end if self.content.wrap and clip then clip() end end if border and border.colors then border_colors = border.colors border_color = checkColors(self.hold, self.hover, border_colors[3],border_colors[2],border_colors[1]) if border_color then for b=0,border.width-1 do rectb(tempX+b, tempY+b, self.w-2*b, self.h-2*b, border_color) end end end if border and border.sprites then border_key = border.key or -1 border_sprites = checkColors(self.hold, self.hover,border.sprites[3],border.sprites[2],border.sprites[1]) if border_sprites then clip(tempX+8,tempY,self.w-16+1,self.h) for x=8,self.w-9,8 do spr(border_sprites[2], tempX+x, tempY, border_key, 1, 0, 0) spr(border_sprites[2], tempX+x, tempY+self.h-8, border_key, 1, 0, 2) end clip() spr(border_sprites[1], tempX, tempY, border_key, 1, 0, 0) spr(border_sprites[1], tempX+self.w-8, tempY, border_key, 1, 0, 1) clip(tempX,tempY+8,self.w,self.h-16+1) for y=8,self.h-9,8 do spr(border_sprites[2], tempX, tempY+y, border_key, 1, 0, 3) spr(border_sprites[2], tempX+self.w-8, tempY+y, border_key, 1, 2, 1) end clip() spr(border_sprites[1], tempX+self.w-8, tempY+self.h-8, border_key, 1, 0, 2) spr(border_sprites[1], tempX, tempY+self.h-8, border_key, 1, 0, 3) end end if icon and icon.sprites and #icon.sprites > 0 then sprite = ((self.hold and icon.sprites[3]) and icon.sprites[3]) or ((self.hover and icon.sprites[2]) and icon.sprites[2]) or icon.sprites[1] sprite_offset = icon.offset or {x=0,y=0} icon.align = icon.align or {x=0,y=0} spr(sprite, (tempX+(icon.align.x==1 and self.w*.5-((icon.scale*8)/2) or (icon.align.x==2 and self.w-(icon.scale*8) or 0))+sprite_offset.x), (tempY+(icon.align.y==1 and self.h*.5-((icon.scale*8)/2) or (icon.align.y==2 and self.h-(icon.scale*8) or 0))+sprite_offset.y), icon.key, icon.scale,icon.flip, icon.rotate, icon.w, icon.h) end --draw text --set color for text if text and text.print then text_colors = text.colors or {15,15,15} text_colors[1] = text_colors[1] or 15 if not text.font and type(text.colors[1]) == "table" then trace("If text.font is true, then text.colors has to be array of numbers!", 6) trace("Traceback: Element with text:\""..text.print.."\"") exit() end -- set color for text acording to mouse state text_color = checkColors(self.hold,self.hover,text_colors[3],text_colors[2],text_colors[1]) -- set color for text shadow if text.shadow then text_shadow = text.shadow text_shadow_color = checkColors(self.hold, self.hover,text_shadow.colors[3],text_shadow.colors[2],text_shadow.colors[1]) text_shadow_offset = text_shadow.offset or {x=1, y=1} end -- get text size text_offset = text.offset or {x = 0, y = 0} if text.font then text.space = text.space or {w=8,h=8} text_width, text_height = ticuare.font(text.print,0,200, -1, text.key, text.space.w, text.space.h, text.fixed, text.scale) else text_width, text_height = ticuare.print(text.print,0,200, -1, text.fixed, text.scale) end -- align text in x axis text_align = text.align or {x=0,y=0} text_x = (text_align.x==1 and tempX+((self.w*.5)-(text_width*.5))+text_offset.x or (text_align.x==2 and tempX+((self.w)-(text_width))+text_offset.x-border_width or tempX+text_offset.x+border_width)) text_y = (text_align.y==1 and tempY+((self.h*.5)-(text_height*.5))+text_offset.y or (text_align.y==2 and tempY+((self.h)-(text_height))+text_offset.y-border_width or tempY+text_offset.y+border_width)) -- drawing text and text shadow if text.font then if type(text_shadow_color)=="table" then ticuare.font(text.print, text_x+text_shadow_offset.x, text_y+text_shadow_offset.y, text_shadow_color, text.key, text.space.w, text.space.h, text.fixed, text.scale) end ticuare.font(text.print, text_x, text_y, text_color, text.key, text.space.w, text.space.h, text.fixed, text.scale) else if text_shadow_color then ticuare.print(text.print, text_x+text_shadow_offset.x, text_y+text_shadow_offset.y, text_shadow_color, text.fixed, text.scale) end ticuare.print(text.print, text_x, text_y, text_color, text.fixed, text.scale) end end end end -- -- Content -- function ticuare:renderContent() local tx, ty, border, offsetX, offsetY, align align = self.align tx = self.x-(align.x==1 and self.w*.5 or (align.x==2 and self.w or 0)) ty = self.y-(align.y==1 and self.h*.5-1 or (align.y==2 and self.h-1 or 0)) border = self.border and self.border.width or 1 offsetX = tx-(self.content.scroll.x or 0)*(self.content.w-self.w) + border offsetY = ty-(self.content.scroll.y or 0)*(self.content.h-self.h) + border self.drawContent(self,offsetX,offsetY) end function ticuare:Content(f) self.drawContent = f return self end function ticuare:scroll(f) if f ~= nil then f.x = f.x or 0 f.y = f.y or 0 if self.content then f.x = (f.x < 0 and 0) or (f.x > 1 and 1) or f.x f.y = (f.y < 0 and 0) or (f.y > 1 and 1) or f.y self.content.scroll.x, self.content.scroll.y = f.x or self.content.scroll.x, f.y or self.content.scroll.y end return self else if self.content then return self.content.scroll end end end -- -- Miscellaneous -- function ticuare.update(mouse_x, mouse_y, press) local me, elements = ticuare.me, ticuare.elements local mouse_event, focused, updateQueue, elemt = me.nothing, false, {}, nil if type(mouse_x)=="table" then press = mouse_y end if mouse_x then if ticuare.click and not press then ticuare.click = false mouse_event = me.noclick ticuare.draging_obj = nil elseif not ticuare.click and press then ticuare.click = true mouse_event = me.click ticuare.draging_obj = nil end --update every element/window first... for i = 1, #elements do table.insert(updateQueue, elements[i]) end table.sort(updateQueue, function(a, b) return a.z > b.z end) -- sort acording to z index for i = 1, #updateQueue do elemt = updateQueue[i] if elemt then if type(mouse_x)=="table" then if elemt:updateSelf{ focused_element=mouse_x, press=press, event=(focused or not elemt.activity) and me.none or mouse_event } then focused = true end elseif mouse_x and mouse_y and type(mouse_x)~="table" then if elemt:updateSelf{ mouse_x=mouse_x, mouse_y=mouse_y, press=press, event=((focused or (ticuare.draging_obj and ticuare.draging_obj.obj ~= elemt)) or not elemt.activity) and me.none or mouse_event } then focused = true end else error("Wrong arguments for update()") end end end --...then update their anchors for i = #elements, 1, -1 do if elements[i] then elements[i]:updateTrack() end end end end function ticuare.draw() local drawQueue = {} for i = 1, #ticuare.elements do if ticuare.elements[i].draw then table.insert(drawQueue, ticuare.elements[i]) end end table.sort(drawQueue, function(a, b) return a.z < b.z end) for i = 1, #drawQueue do drawQueue[i]:drawSelf() end end -- -- Methods -- --Creation / Linking function ticuare:style(style) if self.type == "group" then for k,v in pairs(self.elements) do mergeTables(v, copyTable(style), false) end else mergeTables(self, copyTable(style), false) end return self end function ticuare:anchor(other) if self.type == "group" then for k,v in pairs(self.elements) do v:anchor(other) end else local bounds, b_x_min, b_x_max, b_y_min, b_y_max = self.drag.bounds, nil, nil, nil, nil if bounds and bounds.x then b_x_min = bounds.x[1] - other.x b_x_max = bounds.x[2] - other.x elseif bounds and bounds.y then b_y_min = bounds.y[1] - other.y b_y_max = bounds.y[2] - other.y end self.track = {ref = other, d = {x = self.x-other.x, y = self.y-other.y}, b={x={b_x_min,b_x_max},y={b_y_min,b_y_max}}} end return self end -- assign element to group function ticuare:group(group,name) if name then group.elements[name] = self else table.insert(group.elements,self) end return self end -- Active function ticuare:active(bool) if bool ~= nil then if self.type == "group" then for k,v in pairs(self.elements) do v:active(bool) end else self.activity = bool end return self else if self.type == "group" then local result = {} for k,v in pairs(self.elements) do result[k] = v:active() end return result else if self.activity ~= nil then return self.activity end end end end -- Visible function ticuare:visible(bool) if bool ~= nil then if self.type == "group" then for k,v in pairs(self.elements) do v:visible(bool) end else self.visibility = bool end return self else if self.type == "group" then local result = {} for k,v in pairs(self.elements) do result[k] = v:visible() end return result else if self.activity ~= nil then return self.visibility end end end end --Drag function ticuare:dragBounds(bounds) if bounds ~= nil then self.drag.bounds = bounds else return self.drag.bounds end end function ticuare:horizontalRange(n) local bounds = self.drag.bounds if n ~= nil then self.x = bounds.x[1] + (bounds.x[2]-bounds.x[1])*n else assert(bounds and bounds.x and #bounds.x==2, "X bounds error!") return (self.x-bounds.x[1]) / (bounds.x[2]-bounds.x[1]) end end function ticuare:verticalRange(n) local bounds = self.drag.bounds if n ~= nil then self.y = bounds.y[1] + (bounds.y[2]-bounds.y[1])*n else assert(bounds and bounds.y and #bounds.y==2, "Y bounds error!") return (self.y-bounds.y[1]) / (bounds.y[2]-bounds.y[1]) end end --Z-Index function ticuare:index(index,ignoreHZ) if index ~= nil then if self.type == "group" then local lowest for k,v in pairs(self.elements) do if not lowest or v.z < lowest then lowest = v.z end end for k,v in pairs(self.elements) do local ti = v.z-lowest+index v:index(ti) end else self.z = index if not ignoreHZ and index > ticuare.hz then ticuare.hz = index end end else return self.z end return end function ticuare:toFront(hzVal) if hzVal then --hack: to fix problems with some items not having ability to be on top while others are ontop of everything return self:index(hzVal,true) end if self.z < ticuare.hz or self.type == "group" then return self:index(ticuare.hz + 1) end end function ticuare:remove() for i = #ticuare.elements, 1, -1 do if ticuare.elements[i] == self then table.remove(ticuare.elements, i) self = nil end end end function ticuare.empty() for i = 1, #ticuare.elements do ticuare.elements[i] = nil end end -- BASIC METHODS - thus lower first letter function explode_internal(s,id_table,data_table) local delimiter=";" data_table=data_table and data_table or {} id_table=id_table and id_table or {} local n_max=#id_table local val_table={} local lastpos = 1 local n=1 local isEmpty=false for i=1,#s do if string.sub(s,i,i) == delimiter then local id=id_table[n] local new_pos=i-1 local val=string.sub(s, lastpos, new_pos) isEmpty=false if string.len(val)>0 then local isInt=false local isBool=false if val=="true" or val=="false" then val=(val=="true" and true or false) isBool=true else local int=tonumber(val) if int then val=int isInt=true end end else isEmpty=true end i=i+1 n=n+1 if n_max==0 then table.insert(data_table,val) else if lastpos<=new_pos then val_table[id]=val end if n>n_max then n=1 table.insert(data_table,val_table) val_table={} end end lastpos = i end end return data_table end --https://stackoverflow.com/questions/15706270/sort-a-table-in-lua function spairs(t, order) local keys = {} if not t then return function() i = i + 1 if keys[i] then return keys[i], t[keys[i]] end end end for k in pairs(t) do keys[#keys+1] = k end if order then table.sort(keys, function(a,b) return order(t, a, b) end) else table.sort(keys) end local i = 0 return function() i = i + 1 if keys[i] then return keys[i], t[keys[i]] end end end function foreach(t,func) for i,v in spairs(t) do func(v,i) end end function maybe() return math.random()<0.5 end function string.split(inputstr, sep) if sep == nil then sep = "%s" end local t={} ; i=1 for str in string.gmatch(inputstr, "([^"..sep.."]+)") do t[i] = str i = i + 1 end return t end function math.round(num, numDecimalPlaces) local mult = 10^(numDecimalPlaces or 0) return math.floor(num * mult + 0.5) / mult end function math.sign(x) return x<0 and -1 or x>0 and 1 or 0 end function table.copy(t) if t==nil then return nil end local out_table={} for key,val in pairs(t) do out_table[key]=val end return out_table end function table.contains(t, value) for key,val in pairs(t) do if val==value then return true,key end end return false,nil end function table.containsKey(t,key) for k,val in pairs(t) do if k==key then return true,val end end return false,nil end function pix2Tile(val) return math.floor(val/8) end function tile2Pix(val) return math.floor(val*8) end function switchPallete(palette) for i=0,15 do r=tonumber(string.sub(palette,i*6+1,i*6+2),16) g=tonumber(string.sub(palette,i*6+3,i*6+4),16) b=tonumber(string.sub(palette,i*6+5,i*6+6),16) poke(0x3FC0+(i*3)+0,r) poke(0x3FC0+(i*3)+1,g) poke(0x3FC0+(i*3)+2,b) end end function shallowcopy(orig) local t2 = {} for k,v in pairs(orig) do t2[k] = v end return t2 end function deepcopy_old(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in next, orig, nil do copy[deepcopy(orig_key)] = deepcopy(orig_value) end setmetatable(copy, deepcopy(getmetatable(orig))) else -- number, string, boolean, etc copy = orig end return copy end function deepcopy(obj, seen) -- Handle non-tables and previously-seen tables. if type(obj) ~= 'table' then return obj end if seen and seen[obj] then return seen[obj] end -- New table; mark it as seen an copy recursively. local s = seen or {} local res = {} s[obj] = res for k, v in next, obj do res[deepcopy(k, s)] = deepcopy(v, s) end return setmetatable(res, getmetatable(obj)) end function newSplit(s,delimiter) local words={} for w in (s .. delimiter):gmatch("([^"..delimiter.."]*)"..delimiter) do table.insert(words, w) end return words end function printPlus(s,x,y,color,fixed,scale,smallFont) local splitedBySyntax=newSplit(s,"^") local charLen=smallFont and 4 or 6 if false then print(s,x,y,color,fixed,scale,false) else for i=1,#splitedBySyntax do local split=splitedBySyntax[i] local len=string.len(split) if len>0 then if i%2==1 then else local c=tonumber(string.sub(split,1,2)) if c then local sub=string.sub(split,3,#split) split=sub color=c len=len-3 end end print(split,x,y,color,fixed,scale,smallFont) x=x+charLen*len end end end return color end -- CARD CLASS CardClass = {} CardClass.__index= CardClass setmetatable(CardClass, { __call = function (cls, ...) local self = setmetatable({}, cls) self:_init(...) return self end, }) function CardClass:_init(ID,name,sprite,tags,rarity,desc,stats,isSpell) self.id=ID self.name=name self.sprite=sprite self.tags=deepcopy(tags) self.cardType=isSpell and "spell" or "unit" self.rarity=rarity self.desc=desc self.stats=stats self.isSpell=isSpell foreach(tags,function(tag) if tag.funcAfterInit then tag:funcAfterInit(self) end end) return self end function CardClass:CanBeAttacked(otherUnitsOFThisCardSide,enemyAttackingCardObj, deb) deb=false local distractsList={id="DISTRACT",list={}} local tagsList={id="TAGS",list={}} if deb then Logger:Trace("CAN BE ATTACKED CHECK ON:"..self.id..";BY:"..(enemyAttackingCardObj and enemyAttackingCardObj.id or "NIL!"),glMsgType.GAME_LOGIC) end if not enemyAttackingCardObj then return false end local anyoneHasDistract=false if not self.isLeaderCard then otherUnitsOFThisCardSide=shallowcopy(otherUnitsOFThisCardSide) table.insert(otherUnitsOFThisCardSide,(self.isPlayerCard and GameHelper.playerLeaderCard or GameHelper.enemyLeaderCard)) end foreach(otherUnitsOFThisCardSide,function(otherCardObj) local tag=otherCardObj:GetTagByName(glUnitTags.DISTRACT.name,true) if anyoneHasDistract or otherCardObj:GetTagByName("DISTRACT")~=nil then if deb then Logger:Trace(" UNIT:"..otherCardObj.id.." HAS DISTRACT",glMsgType.GAME_LOGIC) end anyoneHasDistract=true table.insert(distractsList.list,otherCardObj) end end) local check0=enemyAttackingCardObj.stats.attack.cur>0 local check1=true local check2=true if deb then Logger:Trace("anyoneHasDistract:"..(anyoneHasDistract and 1 or 0),glMsgType.GAME_LOGIC) end if anyoneHasDistract then check1= self:GetTagByName(glUnitTags.DISTRACT.name)~=nil if deb then Logger:Trace(" BUT ATTACKED UNIT ALSO HAS DISTRACT",glMsgType.GAME_LOGIC) end end local check3=true if enemyAttackingCardObj then for i=1,(self.isLeaderCard and RuleHelper.numberOfActiveTagsInLeader or RuleHelper.numberOfActiveTagsInUnit) do local tag=self.tags[i] if tag and tag.funcCheckIfCanBeAttackedBy then local tC=tag:funcCheckIfCanBeAttackedBy(self,enemyAttackingCardObj,self.cardGUI,enemyAttackingCardObj.cardGUI,false) check3=check3 and tC if not tC then table.insert(tagsList.list,tag) end if deb and tag.id then Logger:Trace(" ATTACKED UNIT DID TAG CHECK FOR TAG:"..tag.id.." AND CAN CONTINUE:"..(check3 and 1 or 0),glMsgType.GAME_LOGIC) end end end end if deb then Logger:Trace(" END RESULT:"..((check0 and check1 and check3) and 1 or 0),glMsgType.GAME_LOGIC) end return check0 and check1 and check3,{distractsList,tagsList} end function CardClass:DeepCopy(notInitTags) --you can't rely on deepcopy function itself, as some thing will not be initialized local new = deepcopy(self) if self.isSpell then new.stats=GameHelper:InitSpellCardStatsTable(self.stats.manaCost.max,self.stats.spellPower.max) new.stats.manaCost.cur=self.stats.manaCost.cur new.stats.spellPower.cur=self.stats.spellPower.cur else new.stats=GameHelper:InitUnitCardStatsTable(self.stats.hp.max,self.stats.armor.max,self.stats.attack.max,self.stats.manaCost.max) new.stats.hp.cur=self.stats.hp.cur new.stats.armor.cur=self.stats.armor.cur new.stats.attack.cur=self.stats.attack.cur new.stats.manaCost.cur=self.stats.manaCost.cur end new.tags=deepcopy(self.tags) foreach(new.tags,function(tag) tag.data=deepcopy(tag.data) end) if notInitTags then return new end foreach(new.tags,function(tag) --TODO: change this to gettagbypos if tag.funcOnCreatingThisTagOnUnit then tag:funcOnCreatingThisTagOnUnit(new) end if tag.funcAfterInit then tag:funcAfterInit(new) end end) return new end function CardClass:CanExecuteAttack(deb) if deb then Logger:Trace("CAN UNIT EXECUTE ATTACK CHECK ON:"..self.id..";BY:"..(self.isPlayerCard and "PLAYER" or "AI"),glMsgType.GAME_LOGIC) end local check1= self.stats.attacksAvail.cur>0 and self.stats.hp.cur>0 and self.stats.attack.cur>0 if deb then Logger:Trace(" ATTACK ALLOWS:"..(check1 and 1 or 0)..";AVAIL:"..self.stats.attacksAvail.cur..";ATK:"..self.stats.attack.cur,glMsgType.GAME_LOGIC) end local check2=true foreach(self.tags,function(tag) if tag.funcOnCheckingIfUnitCanAttack then check2=check2 and tag:funcOnCheckingIfUnitCanAttack(self) if deb then if tag.id then Logger:Trace(" TAG CHECK FOR TAG:"..tag.id.." AND CAN CONTINUE:"..(check2 and 1 or 0),glMsgType.GAME_LOGIC) else Logger:Error(" TAG DOESNT HAVE PROPER ID ATTACHED",glMsgType.GAME_LOGIC) end end end end) if deb then Logger:Trace(" TAG ALLOWS:"..(check2 and 1 or 0),glMsgType.GAME_LOGIC) end return check1 and check2 end function CardClass:InsertTag(tagObj,simulateOnly) Logger:Debug("Inserting tag:"..(tagObj and tagObj.name or "NIL"),glMsgType.TAG) local max=self.isLeaderCard and 6 or 3 while (#(self.tags)>=max) do self:RemoveTagByPos(1,simulateOnly) end table.insert(self.tags,tagObj) end function CardClass:RemoveTagByObj(tagObj,simulateOnly) foreach(self.tags,function(v,k) if v==tagObj then self:RemoveTagByPos(k,simulateOnly) end end) end function CardClass:RemoveTagByPos(posInTable,simulateOnly) if posInTable>0 and posInTable<=(#self.tags) then local cardGUI=self.cardGUI if cardGUI and not simulateOnly then ParticleHelper:CreateRemoveTagFX(cardGUI:getCenterX(),cardGUI:getCenterY(),0) end local tag=self.tags[posInTable] if tag and tag.funcOnRemovingThisTag then tag:funcOnRemovingThisTag(self,simulateOnly) end table.remove(self.tags,posInTable) end end function CardClass:GetTagByName(tagName,deb) deb=false if deb then Logger:Trace("checking for tagName:"..tagName.." in:"..self.id,glMsgType.TAG) end local tag=nil return GameHelper:FindTagInCard(self,tagName) end function CardClass:GetTagByPos(posInTable) if posInTable>0 and posInTable<=#self.tags then return self.tags[posInTable] end end function CardClass:GetTagByObj(objTag) local tag=nil foreach(self.tags,function(v,k) if v==objTag then tag=v end end) return tag end -- LEADER CARD CLASS LeaderClass = {} LeaderClass.__index= LeaderClass setmetatable(LeaderClass, { __index = CardClass, -- self is what makes the inheritance work __call = function (cls, ...) local self = setmetatable({}, cls) self:_init(...) return self end, }) function LeaderClass:_init(ID,name,sprite,tags,rarity,desc,stats,unitIDBasedOn) CardClass._init(self,ID,name,sprite,tags,rarity,desc,stats) self.artifactsIDList={} self.bucketsList={} self.isLeaderCard=true self.unitIDBasedOn=unitIDBasedOnīĻ return self end function LeaderClass:SpendMana(manaCost) local toolbar=(self.isPlayerCard and glPlayerToolbar or glEnemyToolbar) local x=toolbar.x+4+self.stats.manaVisualCount.cur*8 local y=toolbar.y+(self.isPlayerCard and 4 or 8) self.stats.manaCount:sub(manaCost) for i=manaCost,1,-1 do AsyncQueueLogicHelper:AddToQueue(function(data) ParticleHelper:CreateManaFX(data.x,data.y,true,0) data.self.stats.manaVisualCount:sub(1) SfxHelper:PlaySFX(glSFXSpendManaData.id,glSFXSpendManaData.notesList[manaCost-i+1]) end,{x=x-i*8,y=y,self=self},0.15*i) end end function LeaderClass:RestoreMana(amount,ignoreFX) local stats=self.stats if not amount then amount=stats.manaCount.max end local toolbar=(self.isPlayerCard and glPlayerToolbar or glEnemyToolbar) local start=stats.manaVisualCount.cur local x=toolbar.x+4+start*8 local y=toolbar.y+(self.isPlayerCard and 7 or 8) stats.manaCount:add(amount) stats.manaVisualCount.max=stats.manaCount.max local n=stats.manaCount.cur-start if GameHelper.tutorialPhase~=40 and (GameHelper.tutorialPhase<0 or GameHelper.tutorialPhase>20) then for i=0,n do AsyncQueueLogicHelper:AddToQueue(function(data) data.self.stats.manaVisualCount:add(1) if data.notIgnoreFX then ParticleHelper:CreateManaFX(data.x,data.y,false,0) SfxHelper:PlaySFX(glSFXGainManaData.id,glSFXGainManaData.notesList[i+1]) end end,{x=x+i*8,y=y,self=self,notIgnoreFX=not ignoreFX},0.15*i) end end end function LeaderClass:DeepCopy(notInitTags) Logger:Debug("deep copying:"..self.id,glMsgType.GAME_LOGIC) local new = deepcopy(self) new.stats=GameHelper:InitLeaderCardStatsTable(self.stats.hp.max,self.stats.armor.max,self.stats.attack.max) new.stats.hp.cur=self.stats.hp.cur new.stats.armor.cur=self.stats.armor.cur new.stats.attack.cur=self.stats.attack.cur new.stats.manaCost.cur=self.stats.manaCost.cur if notInitTags then return new end foreach(new.tags,function(tag) if tag.funcAfterInit then tag:funcAfterInit(new) end end) return new end -- TUTORIAL HELPER CLASS TutorialHelper = {} TutorialHelper.__index = TutorialHelper TutorialHelper.id="TutorialHelper" function TutorialHelper:CheckIfTutorialIsActive() return GameHelper.tutorialPhase>0 and GameHelper.tutorialPhase<60 end function TutorialHelper:CheckForEndOfTheMatch() if not GameHelper.tutorialStepFinished then GameHelper.tutorialStepFinished=true GameHelper.playerWon= GameHelper.enemyLeaderCard.isDeleted if GameHelper.playerWon then if GameHelper.tutorialPhase<20 then GameHelper.tutorialPhase=20 elseif GameHelper.tutorialPhase<30 then GameHelper.tutorialPhase=30 elseif GameHelper.tutorialPhase<40 then GameHelper.tutorialPhase=40 elseif GameHelper.tutorialPhase==49 then local tutFunc3=function(ref) glTutorialDialog=GUIHelper:CreateTutorialDialog(function(ref) GameHelper.playedTutorial=1 GameHelper:SaveMoreOptionsToPMEM() GameHelper.tutorialPhase=-10 reset() end,{"Your best friend,","possibly a lover,","perhaps the parent figure,","wishing you all the best!","","Always yours","^14Tutorial Box the Third, MD, PhD"}) end local tutFunc2=function(ref) glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc3,{"Feel free to move into game mode","or restart tutorial if needed!","^14There is more in this game to learn","^14but you've learned the basics","and rest you can learn by playing!"}) end local tutFunc1=function(ref) glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc2,{"If you could just click ok... to prove...","HA! NVM!","YOU KNOW THIS STUFF!"}) end AsyncQueueLogicHelper:AddToQueue(function() glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc1,{"You've beaten all the tutorials!","That was something!","^14And you've proven so much!","^14like how you can read!","Wow!"})end,{},1) return else GameHelper.tutorialPhase=-10 end glTutorialDialog:hide() glTutorialDialog:remove() AsyncQueueLogicHelper:AddToQueue(function(data) GameHelper.tutorialStepFinished=false GameHelper.finishingMatch=true GameHelper:PreInitAndShowSummaryScreen() GameHelper:InitMatchStart() end,{},1.5) else if GameHelper.tutorialPhase<20 then GameHelper.tutorialPhase=10 elseif GameHelper.tutorialPhase<30 then GameHelper.tutorialPhase=20 elseif GameHelper.tutorialPhase<40 then GameHelper.tutorialPhase=30 else GameHelper.tutorialPhase=40 end glTutorialDialog:hide() glTutorialDialog:remove() local tutFunc1=function(ref) AsyncQueueLogicHelper:AddToQueue(function(data) GameHelper.tutorialStepFinished=false GameHelper.finishingMatch=true GameHelper:PreInitAndShowSummaryScreen() GameHelper:InitMatchStart() end,{},0.1) end AsyncQueueLogicHelper:AddToQueue(function() glTutorialDialog=GUIHelper:CreateTutorialDialog(tutFunc1,{"No worries!","Remember, you have gift of reading!","...","You can do this!","I will restart tutorial for you!"})end,{},1.5) end end end -- LOGGER CLASS Logger = {} Logger.__index = Logger Logger.levels={ERROR=-1,INFO=0,DEBUG=1,TRACE=2} Logger.logLvl=1 function Logger:Init() self.fontWidth=8 self.fontHeight=8 self.fontLetterSpacing=0 self.messageArray={} self.FPSTable={} self.msgToIgnoreList={} self.linesCount=5 self.msgSizeX=120 self.charsCount=math.floor(self.msgSizeX/8) self.firstMsgPositionX=100 self.firstMsgPositionY=100 self.fpsPositionX=0 self.fpsPositionY=0 self.render=true self.FPS={value =0,frames =0,lastTime=-1000} self.averageFPS=0 glSecondsElapsed=0 --this will create known columns for csv trace("Time;Level;Type;Message") end ---@param typeID glMsgType used to identify type of msg, prefix message with it and filter if its in msgToIgnoreList function Logger:RegisterToIgnore(typeID) if typeID and not table.contains(self.msgToIgnoreList,typeID) then table.insert(self.msgToIgnoreList,typeID) Logger:Debug("Registered msg type to ignore:"..typeID,glMsgType.LOGGER) end end ---@param typeID glMsgType used to identify type of msg, prefix message with it and filter if its in msgToIgnoreList function Logger:UnregisterToIgnore(typeID) if typeID then local c,key= table.contains(self.msgToIgnoreList,typeID) if c then table.remove(self.msgToIgnoreList,key) Logger:Debug("Unregistered msg type to ignore:"..typeID,glMsgType.LOGGER) end end end function Logger:writeMsg(msg,typeID,prefix,level) if level>self.logLvl then return end if typeID then if table.contains(self.msgToIgnoreList,typeID) then --Logger:Trace("Msg ignored:"..typeID,glMsgType.LOGGER) return end end if self.linesCount then local len=#self.messageArray while(len>=self.linesCount) do local first=self.messageArray[1] table.remove(self.messageArray,1) len=#self.messageArray end end local pref=(typeID and (prefix or "")..typeID..";" or "") local m=math.floor(glSecondsElapsed)..";"..level..";"..pref..(msg or "nil val") local spacesCount=self.charsCount-#m for i=0,spacesCount-1 do m=m.." " end table.insert(self.messageArray,m) trace(m) end function Logger:log(msg,typeID,prefix,level) if not msg then return end if type(msg)=="table" then Logger:writeMsg("CONTENTS OF TABLE:",typeID,prefix,level) for k, v in pairs(msg) do if type(v)=="table" then Logger:writeMsg(" "..k,typeID,prefix,level) Logger:log(v,typeID,prefix,level) else local s=v if type(v)=="boolean" then s=(v and "True" or "False") elseif type(v)=="table" then s="table" elseif type(v)=="function" then s="function" end Logger:writeMsg(" "..k..":"..(s or "NIL"),typeID,prefix,level) end end elseif type(msg)=="boolean" then Logger:writeMsg(msg and "True" or "False",typeID,prefix,level) else Logger:writeMsg(msg,typeID,prefix,level) end end ---@param msg string ---@param typeID glMsgType not required, used to identify type of msg, prefix message with it and filter if its in msgToIgnoreList function Logger:Error(msg,typeID) Logger:log(msg,typeID,"!ERROR!;",self.levels.ERROR) end ---log on most important layer of logs ---@param msg string ---@param typeID glMsgType not required, used to identify type of msg, prefix message with it and filter if its in msgToIgnoreList ---@param prefix string will be insterted before msg or typeID if its avail. function Logger:Info(msg,typeID,prefix) Logger:log(msg,typeID,prefix,self.levels.INFO) end ---log for debugging ---@param msg string ---@param typeID glMsgType not required, used to identify type of msg, prefix message with it and filter if its in msgToIgnoreList ---@param prefix string will be insterted before msg or typeID if its avail. function Logger:Debug(msg,typeID,prefix) Logger:log(msg,typeID,prefix,self.levels.DEBUG) end ---log for describing every minute detail that should be omitted generally ---@param msg string ---@param typeID glMsgType not required, used to identify type of msg, prefix message with it and filter if its in msgToIgnoreList ---@param prefix string will be insterted before msg or typeID if its avail. function Logger:Trace(msg,typeID,prefix) Logger:log(msg,typeID,prefix,self.levels.TRACE) end --- call this function in Update(timeDelta) function Logger:Update(timeDelta) glSecondsElapsed = glSecondsElapsed + timeDelta end function Logger:Render() if not self.render then return end local n=0 local drawFPS=false if drawFPS then self:RenderFPS() end end function Logger:GetFPSValue() --https://tic80.com/play?cart=123 if (time()-self.FPS.lastTime <= 1000) then self.FPS.frames=self.FPS.frames+1 else self.FPS.value=self.FPS.frames self.FPS.frames=0 self.FPS.lastTime=time() end return self.value end function Logger:CalculateFPS(timeDelta) table.insert(self.FPSTable,(1/timeDelta)) local l=#self.FPSTable if l<10 then return end local n=0 for i,v in ipairs(self.FPSTable) do n=n+v end self.averageFPS=n/l table.remove(self.FPSTable,1) self:GetFPSValue() end function Logger:RenderFPS() rect(self.fpsPositionX,self.fpsPositionY,22,13,5) print(self.FPS.value.."|"..self.averageFPS,self.fpsPositionX,self.fpsPositionY,15,false,1,true) end function InitCSVData() glSpellsCSVNames="id;name;manaCost;sprite;type;rarity;tags;spellPower;turnedOff;" glSpellsCSVData="S000;Small Fireball;2;128;DMG;N;DAMAGE_UNIT;2;;S001;Greatest Fireball Ever;9;130;DMG;L;DAMAGE_UNIT;9;;S002;Great Fireball;4;132;DMG;R;DAMAGE_UNIT;4;;S003;Small Heal;2;134;BUFF;N;HEAL;3;;S004;Apply DISTRACT TAG;3;136;DEBUFF;R;APPLY_DISTRACT;2;;S005;Great Heal;4;134;BUFF;N;HEAL;6;;S006;Apply POISONED TAG;4;140;DEBUFF;L;APPLY_POISONED;1;;S007;Bigger DMG to ALL units;3;238;DMG;N;DAMAGE_ALL;3;;S008;Apply NIMBLE TAG;3;200;BUFF;R;APPLY_NIMBLE;1;;S009;Attack buff;2;172;BUFF;R;BUFF_ATK;1;;S010;Great Attack buff;5;172;BUFF;R;BUFF_ATK;3;;S011;Bigger water wave;7;166;DMG;N;WAVE;4;;S012;Great Armor Buff;3;172;BUFF;R;BUFF_ARMOR;5;;S013;Health Buff;2;172;BUFF;N;BUFF_HP;2;;S014;Great Health Buff;4;172;BUFF;R;BUFF_HP;5;;S015;Summon U011;1;174;SUMMON;R;SUMMON_U011;1;;S016;Summon two U001;2;174;SUMMON;R;SUMMON_U001;2;;S017;Small Health Cut;2;204;DEBUFF;N;CUT_HP;1;;S018;Health Cut;5;204;DEBUFF;N;CUT_HP;3;;S019;Apply RANGED TAG;3;160;BUFF;R;APPLY_RANGED;1;;S020;Apply INSPIRES TAG;4;192;BUFF;L;APPLY_INSPIRES;1;;S021;Small Attack Cut;2;204;DEBUFF;R;CUT_ATK;1;;S022;Attack Cut;5;204;DEBUFF;N;CUT_ATK;3;;S023;DMG to ALL units;1;238;DMG;N;DAMAGE_ALL;1;;S024;Water Wave;3;166;DMG;N;WAVE;2;;S025;Remove First Tag;3;230;DEBUFF;R;REMOVETAG_FIRST;1;;S026;Remove 2 First Tags;6;230;DEBUFF;R;REMOVETAG_FIRST;2;;S027;Remove Last Tag;3;232;DEBUFF;R;REMOVETAG_LAST;1;;S028;Remove 2 Last Tags;6;232;DEBUFF;R;REMOVETAG_LAST;2;;S029;Find 1 Card;2;234;BUFF;N;FIND;1;;S030;Draw 2 Cards;3;236;BUFF;N;DRAW;2;;S031;Apply SLOW TAG;3;206;DEBUFF;R;APPLY_SLOW;1;;S032;Apply Spell Power Buff;3;172;BUFF;L;BUFF_SPELLPWR;1;;S033;Apply Spell Power Cut;3;204;DEBUFF;L;CUT_SPELLPWR;1;;S034;Steal Last Tag;4;228;DEBUFF;L;STEALTAG_LAST;1;;S035;Apply DRAIN TAG;4;226;BUFF;R;APPLY_DRAIN;1;;S036;Steal First Tag;4;228;DEBUFF;L;STEALTAG_FIRST;1;;" glUnitsCSVNames="id;name;manaCost;sprite;type;rarity;tags;attack;hp;armor;turnedOff;" glUnitsCSVData="A001;Rat Queen;2;224;Animal;R;NIMBLE;2;2;0;;A002;Very Sick Rat;1;296;Animal;N;POISON;1;1;0;;A003;Petting Goat;1;298;Animal;N;DASH;1;1;0;;A004;Young Goat;2;300;Animal;N;;3;2;0;;A005;Forest Goat;3;302;Animal;N;DASH;3;3;0;;A006;Mature Boar;4;324;Animal;N;;4;3;0;;A007;Armorboar;5;326;Animal;R;;3;3;5;;A008;Death Adder;4;330;Animal;R;VENOM;1;1;1;;A009;Python;3;332;Animal;N;DASH,POISON;1;3;1;;A010;Sidewinder;5;334;Animal;R;DASH,VENOM;1;2;1;;A011;Young Porcupine;2;354;Animal;R;DASH,PIERCE;1;1;1;;A012;Adult Porcupine;3;356;Animal;N;PIERCE;3;2;2;;A013;Porcupine King;6;358;Animal;R;PIERCE,INSPIRES;2;5;4;;A014;Young Moose;4;360;Animal;N;CLEAVE;3;4;0;;A015;Moose;7;362;Animal;N;CLEAVE;4;7;0;;A016;King Moose;7;364;Animal;L;CLEAVE,INSPIRES;3;8;0;;A017;Skunk;2;366;Animal;N;DISARM,DISTRACT;1;3;0;;A018;Young Monkey;2;384;Animal;N;DRAW;1;3;0;;A019;Monkey;4;386;Animal;N;STEAL,NIMBLE;1;4;0;;A020;Baboon King;5;388;Animal;N;INSPIRES,DISTRACT;1;6;0;;A021;Very Opinionated Cow;2;392;Animal;N;DISTRACT;0;4;0;;A022;Goliath Beetle;1;394;Animal;R;;1;1;2;;A023;Ostrich;4;396;Animal;R;FEARED,NIMBLE;3;3;0;;A024;Very Snuggly Bear ;6;416;Animal;R;FEARED;4;5;1;;A025;Very Possessive Giraffe;7;418;Animal;N;DASH,STEAL;3;9;0;;A026;Elephant;9;420;Animal;R;FEARED;5;11;1;;A027;Young Bat;2;424;Animal;R;DRAIN;1;3;0;;A028;Great Bat;8;428;Animal;R;FEARED,DRAIN;4;9;0;;A029;Legendary Wolf Leader;5;110;Animal;L;INSPIRES,DASH,FEARED;2;4;0;;H000;Peasant;1;430;Human;N;;1;1;1;;H001;Village Bully;1;448;Human;N;STEAL;1;1;0;;H002;Village Militia;2;450;Human;N;;2;1;2;;H003;Local Bandit;2;452;Human;N;STEAL;1;1;2;;H004;Local Strongman;1;454;Human;R;DISTRACT;1;2;0;;H005;Village Herald;3;458;Human;R;DRAW;1;2;2;;H006;Marauder;3;460;Human;N;FEARED;3;1;2;;H007;Local Bandit Chieftain;3;462;Human;R;STEAL,FEARED;2;2;3;;H008;Bounty Hunter;3;32;Human;N;DISARM,DASH;2;1;3;;H009;Archer Guard;3;34;Human;N;RANGED;2;1;2;;H010;Road Bandit;4;36;Human;N;STEAL;1;1;4;;H011;Town Herald;4;38;Human;R;DRAW,DRAW;2;1;4;;H012;Swordsman;4;40;Human;N;PIERCE,DASH;3;1;2;;H013;Assassin;6;42;Human;R;POISON,DASH,NIMBLE;1;1;3;;H014;Bandit Ringleader;5;44;Human;R;CLEAVE,FEARED;3;3;3;;H015;Village Medic;3;46;Human;N;HEALER;0;2;0;;H016;Church Cleric;5;64;Human;N;HEALER,DRAW;1;2;2;;H017;King's Watch;6;66;Human;R;FEARED,CLEAVE;3;2;5;;H018;Queen's Watch;5;68;Human;R;FEARED,NIMBLE;3;2;5;;H019;Legendary Strongman;6;70;Human;L;DISTRACT,FEARED,DISARM;3;3;3;;H020;Legendary Fencer;7;72;Human;L;FEARED,DASH,NIMBLE;3;1;5;;H021;Legendary Bounty Hunter;8;74;Human;L;STEAL,DRAW,NIMBLE;4;2;4;;H022;Local Huntsman;1;106;Human;N;RANGED;1;1;0;;H023;Ranged Guard;4;108;Human;N;RANGED;3;1;3;;U000;Zombie;1;76;Undead;N;;1;2;0;;U001;Skeleton;1;78;Undead;N;;2;1;0;;U002;Skeleton Priest;3;98;Undead;R;SUMMON_U001,SUMMON_U001;1;1;1;;U003;Flesh Abomination;3;100;Undead;N;DISTRACT;2;5;0;;U004;Necromancer;3;102;Undead;N;SUMMON_U000;2;1;0;;U005;Very Concerned, Yet Still Undead, Teacher;4;104;Undead;N;SUMMON_U004;2;1;0;;U006;Lesser Deamon;4;292;Undead;R;DISTRACT,CLEAVE;2;4;0;;U007;Wraith;4;320;Undead;N;DISTRACT;3;5;0;;U008;Deamon;6;390;Undead;N;FEARED,CLEAVE;3;7;0;;U009;Fiery Imp;4;352;Undead;L;RANGED,NIMBLE,DASH;2;2;0;;U010;Imp;4;398;Undead;R;DASH,RANGED;3;2;0;;U011;Old Zombie;2;290;Undead;N;POISON;1;2;0;;U012;Vampire;5;322;Undead;R;DRAIN,DASH;4;5;0;;U013;Giant Skeleton Archer;7;328;Undead;R;RANGED,PIERCE;5;5;0;;U014;Ghost;5;426;Undead;N;DISTRACT;0;9;0;;U015;Undead Priest;2;456;Undead;R;SUMMON_U011;1;1;0;;U016;Ghoul;6;96;Undead;N;SLOW;8;7;0;;U017;Undead Assassin;5;288;Undead;R;DRAW,DRAW,POISON;2;2;2;;U018;Flesh Amalgam;7;422;Undead;N;SLOW,DISTRACT;2;11;0;;U019;Gargoyle;7;2;Undead;N;SLOW;4;10;0;;U020;Undead Fire Priest;9;4;Undead;L;SUMMON_U009;2;1;0;;U021;Ghoul Fire Priest;9;263;Undead;R;SUMMON_U010,SUMMON_U010;1;1;0;;U022;Very Undead Cow;2;265;Undead;R;DISTRACT,SPELLPWR_UP;0;3;0;;U023;Scared Young Mana Snail;1;198;Undead;N;SPELLPWR_DOWN,SLOW;0;1;3;;U024;Giant Adult Mana Snail;6;194;Undead;R;SPELLPWR_DOWN,SLOW;1;1;10;;U025;Weak Zombie;1;76;Undead;N;;1;1;0;;" glLeadersCSVNames="id;name;sprite;type;rarity;dungeonGenerationInfo;dungeonSubLevelUpgade;tags;attack;hp;armor;unitBasedOn;turnedOff;" glLeadersCSVData="L000;Leader 1;263;Human;N;;;;1;16;0;;;L001;Leader 2;265;Human;N;;;;1;8;8;;;L002;Leader 3;263;Human;N;;;DASH;1;12;4;;;L003;Leader 4;263;Human;N;;;DASH;2;12;0;;;L004;Leader 5;265;Human;N;;;DASH;2;6;6;;;L005;Leader 6;263;Human;N;;;DASH;2;4;8;;;L006;Leader 7;263;Human;N;;;DASH;0;20;0;;;L007;Leader 8;265;Human;N;;;DASH;0;10;10;;;L008;Leader 9;263;Human;N;;;DASH;0;16;4;;;L009;Very Sick Rat;296;Animal;N;{1,DECK031};{0,0,1};POISON;1;14;0;A002;;L010;Rat Queen;224;Animal;N;{1,DECK031};{0,1,1};NIMBLE;1;12;2;A001;;L011;Goat Establishment;302;Animal;N;{1,DECK032};{1,1,0};DASH;1;16;0;A005;;L012;Inspiring Wolf;110;Animal;N;{2,DECK033};{0,3,0};INSPIRES;2;19;1;A029;;L013;Crass Baboon;388;Animal;N;{2,DECK034};{1,2,0};DISTRACT,INSPIRES;0;20;2;A020;;L014;Very Opinionated Cow;392;Animal;N;{1,DECK035};{0,3,0};DISTRACT;0;22;0;A021;;L015;Stealing Giraffe;418;Animal;N;{3,DECK036};{0,2,1};STEAL;3;25;2;A025;;L016;Bundle of Snakes;334;Animal;N;{2,DECK037};{1,1,0};DASH,POISON;1;13;3;A009;;L017;King of Mooses;364;Animal;N;{3,DECK038};{1,1,1};CLEAVE;4;18;4;A015;;L018;Village Bully;454;Human;N;{1,DECK039};{1,1,0};DISTRACT,FEARED;1;14;4;H004;;L019;Village Militia;430;Human;N;{1,DECK040};{1,0,2};SLOW;2;10;7;H000;;L020;Summoning Teacher;104;Undead;N;{1,DECK041};{0,1,1};SUMMON_U000;0;12;2;U004;;L021;Lesser Evil;78;Undead;N;{1,DECK042};{0,2,0};FEARED,SLOW;2;14;0;U001;;L022;Kingshand;66;Human;N;{3,DECK043};{0,0,3};DASH,CLEAVE;3;14;14;H017;;L023;Cleric of healing;64;Human;N;{2,DECK044};{0,1,1};HEALER,DRAW;1;19;3;H016;;L024;Forest Bandit;106;Human;N;{2,DECK045};{1,1,1};FEARED,RANGED;2;14;2;H022;;L025;Assasin;42;Human;N;{2,DECK046};{0,0,3};POISON,NIMBLE;1;13;7;H013;;L026;Vampire Queen;322;Undead;N;{2,DECK047};{0,3,0};DRAIN;2;18;0;U012;;L027;Demon Lord;390;Undead;N;{4,DECK048};{1,2,0};CLEAVE,FEARED;3;20;5;U008;;L028;Bandit Ringleader;44;Human;N;{3,DECK049};{1,1,1};CLEAVE;3;20;8;H014;;L029;All kind of rangers;108;Human;N;{2,DECK050};{1,0,1};RANGED;1;14;6;H023;;L030;Tons of Imps;352;Undead;N;{3.DECK051};{0,3,0};RANGED,DASH;2;18;0;U009;;L031;Summoning Fire Priest;4;Undead;N;{3,DECK000};{0,1,2};SUMMON_U010;2;12;12;U020;;L032;Amalgamations;100;Undead;N;{4,DECK002};{1,2,0};SLOW,DISTRACT;5;34;0;;;L033;Beastmaster;70;Human;N;{4,DECK001};{2,1,0};INSPIRES;3;30;0;;;L034;Undead Grand Magggus;263;Undead;N;{4,DECK052};{0,2,0};SPELLPWR_UP;0;30;12;;;L035;Anti-Magggus;64;Human;N;{4,DECK053};{0,1,1};SPELLPWR_DOWN;4;17;14;;;L036;Armored Armor;68;Human;N;{4,DECK000};{0,0,3};DISTRACT,SLOW;4;5;45;;;L037;Total Summoner;102;Human;N;{4,DECK054};{0,0,3};SUMMON_U001,SUMMON_U001,SUMMON_U001,SUMMON_U001,SUMMON_U001,SUMMON_U001;2;26;8;;;L038;Undead Assasin;288;Undead;N;{4,DECK046};{0,1,1};POISON,NIMBLE,NIMBLE;1;34;3;H013;;L039;Primal Bat;428;Animal;N;{3,DECK047};{1,1,1};FEARED,DRAIN;3;28;0;A028;;L040;Flock of Bats;424;Animal;N;{1,DECK055};{1,1,1};DRAIN;1;18;0;A027;;" glDecksCSVNames="id;name;type;subTypes;startingSize;playerDeck;desc;deckOrder;supportingCardsOrder;keyCards;supportingCards;" glDecksCSVData="DECK000;Protect the Leader!;match;sparing;30;0;Focused on units with DISTRACT to make leader and their weak, but powerful, units protected.;random;ordered;H004,H004,A021,A021,U003,U003,U006,U006,U007,U007,A020,A020,U014,U014,H015,H015,H019,A029;{H016,1,2},{A018,1,2},{H022,0,2},{H023,0,2},{A002,0,1},{A014,0,1},{A012,0,1}{H009,1,2},{A017,1,2},{U010,1,2},{A001,1,2},{A013,1,2};DECK001;Rush the enemy!;match;sparing;30;0;Focused on killing enemy quickly by utilizing units with DASH and DRAW tags. If that isn’t enough then crushing what’s left with units that have PIERCE/POISON/VENOM tags.;random;ordered;A003,A005,A009,A009,A008,A008,H013,A018,A018,H005,H005,H011,H013,U009,U010,U010,U013,U017,H012,H012,A010,A010;{S000,0,2},{S002,0,1},{H016,1,2},{H011,0,1},{A029,0,1},{H008,0,2},{H020,0,1},{H021,0,1},{A025,0,2};DECK002;All the value!;match;sparing;30;0;Focused on maximizing value from each card and the whole deck. It is slow to play but if you survive first turns you will crush enemy later.;random;ordered;H016,U015,U013,U006,U005,U004,H022,H023,A020,U002,S030,S010;{A020,0,1},{A028,0,1},{H017,0,1},{U003,0,1},{U006,0,1},{U014,0,1},{U002,0,1},{H016,0,1},;DECK003;Animal;arena;start;12;1;Semi random deck build with ANIMAL units;random;ordered;A022,A004,A005,A006,A007,S009,S030;{A004,0,1},{A001,0,1},{A017,0,1},{A021,0,1},{A002,0,1},{A014,0,1},{A012,0,1},{A014,0,1},{A020,0,1},{A024,0,1},{A008,0,1},{S009,0,1},{A009,0,1};DECK004;Human;arena;start;12;1;Semi random deck build with HUMAN units;random;ordered;H000,H002,H005,H009,H016,S029,S003,S029;{H001,0,1},{H003,0,1},{H006,0,1},{H007,0,1},{H008,0,1},{H015,0,1},{H010,0,1},{H012,0,1},{H023,0,1},{H014,0,1},{S003,0,1},{H013,0,1},;DECK005;Undead;arena;start;12;1;Semi random deck build with UNDEAD units;random;ordered;U000,U015,U002,U005,U014,S000,S025,U022,S023;{U001,0,1},{U011,0,1},{U015,0,1},{U003,0,1},{U004,0,1},{U006,0,1},{U007,0,1},{U010,0,1},{U012,0,1},{S027,0,1};DECK006;Distract;arena;start;18;1;Semi random deck build around DISTRACT tag;random;ordered;A021,H004,U003,U007,U014,U006,S003,S027;{A020,0,1},{A021,0,1},{H004,0,1},{U003,0,1},{U007,0,1},{U014,0,1},{U006,0,1},{S025,0,1};DECK007;Dash;arena;start;18;1;Semi random deck build around DASH tag;random;ordered;A003,A009,U010,H008,U012,H012,S009,S010,S030;{H008,0,1},{U012,0,1},{H012,0,1},{A025,0,1},{H013,0,1},{S030,0,1};DECK008;Feared;arena;start;18;1;Semi random deck build around FEARED tag;random;ordered;H006,H007,A024,H017,U008,A028,A023,H018,S021,S009;{H006,0,1},{H007,0,1},{A024,0,1},{H017,0,1},{U008,0,1},{A028,0,1},{A023,0,1},{H018,0,1},{A026,0,1},{S021,0,1};DECK009;Ranged;arena;start;18;1;Semi random deck build around RANGED tag;random;ordered;U010,H022,H009,H023,U013;{U010,0,1},{H022,0,1},{H009,0,1},{H023,0,1},{U013,0,1};DECK010;Steal/Disarm;arena;start;24;1;;;;H001,H003,H010,H007,A019,A025,A017,H008;{A017,0,1},{H008,0,1}{H001,0,1},{H003,0,1},{H010,0,1},{H007,0,1},{A019,0,1},{A025,0,1};DECK011;Venom/Poison;arena;start;24;1;;;;A008,A010,H013,A002,U011;{A002,0,1},{U011,0,1},{A008,0,1},{A010,0,1},{H013,0,1};DECK012;Draw/Healing;arena;start;24;1;deck build units with TAG DRAW;random;ordered;A018,H005,H011,U017,H016,H015;{A018,0,1},{H005,0,1},{H011,0,1},{U017,0,1},{H016,0,1},{H015,0,1};DECK013;Draw;arena;start;12;0;deck build units with TAG DRAW and card draw EFFECTS;random;ordered;A018,H005,H011,U017,H016;;DECK014;Healing;arena;start;12;0;deck focused on units with HEALER TAG and healing EFFECTS;random;ordered;H015,H016 ;;DECK015;Steal;arena;start;12;0;;;;H001,H003,H010,H007,A019,A025;;DECK016;Disarm;arena;start;12;0;;;;A017,H008;;DECK017;Cleave;arena;start;12;0;;random;ordered;A014,A015,H014,U006,H017,U008;;DECK018;;;;;0;;;;;;DECK019;Nimble;arena;start;12;0;;random;ordered;A023,H018,A001,A019,H013;;DECK020;Pierce;arena;start;12;0;;random;ordered;A011,A012,H012,A013;;DECK021;Inspires;arena;start;12;0;;random;ordered;;;DECK022;Draw/Healing;arena;start;12;0;deck build units with TAG DRAW and card draw EFFECTS;random;ordered;A018,H005,H011,U017,H016;;DECK023;Venom;arena;start;12;0;;random;ordered;A008,A010,H013;;DECK024;Poison;arena;start;12;0;;random;ordered;A002,U011;;DECK025;Protect the Leader! Boss Deck;match;sparing;30;0;Focused on units with DISTRACT to make leader and their weak, but powerful, units protected.;random;ordered;H004,H004,A021,A021,U003,U003,U006,U006,U007,U007,A020,A020,U014,U014,H015,H015,H019,A029,U009,A016,H019,H020,H021,A029;{H016,1,2},{A018,1,2},{H022,0,2},{H023,0,2},{A002,0,1},{A014,0,1},{A012,0,1}{H009,1,2},{A017,1,2},{U010,1,2},{A001,1,2},{A013,1,2};DECK026;Rush the enemy! Boss Deck;match;sparing;30;0;Focused on killing enemy quickly by utilizing units with DASH and DRAW tags. If that isn’t enough then crushing what’s left with units that have PIERCE/POISON/VENOM tags.;random;ordered;A003,A005,A009,A009,A008,A008,H013,A018,A018,H005,H005,H011,H013,U009,U010,U010,U013,U017,H012,H012,A010,A010,A029,U009,A016,H019,H020,H021;{S000,1,2},{S002,0,1},{H016,1,2},{H011,0,1},{A029,0,1},{H008,0,2},{H020,0,1},{H021,0,1},{A025,0,2};DECK027;All the value! Boss Deck;match;sparing;30;0;Focused on maximizing value from each card and the whole deck. It is slow to play but if you survive first turns you will crush enemy later.;random;ordered;H016,U015,U013,U006,U005,U004,H022,H023,A020,U002,S030,S010,A029,U009,A016,H019,H020,H021;{A020,0,1},{A028,0,1},{H017,0,1},{U003,0,1},{U006,0,1},{U014,0,1},{U002,0,1},{H016,0,1};DECK028;Summoner;arena;start;12;1;Deck build around units that summon other units;static;ordered;U002,U002,U004,U004,U005,U005,U015,U015,U020,S015,S016,S000;;DECK029;PURE MAGE;arena;start;16;1;Deck build with offensive and defensive EFFECTs;static;ordered;S000,S011,S001,S002,S002,S004,S031,S011,S009,S015,S016,S025,S028,S030,S029,S007;;DECK030;Venom/Poison;arena;start;12;1;Semi random deck build around POISON/VENOM tags;random;ordered;A008,A010,H013,A002,U011,U015,S006;{A002,0,1},{U011,0,1},{A008,0,1},{A010,0,1},{H013,0,1},{U015,0,1},{U017,0,1};DECK031;Just Rats 1;run;.;12;0;;static;ordered;A002,A001,A002,A001,A022,A022,S018,S030,A021;{A002,0,1},{A001,0,1},{A022,0,1},{S018,0,1},{S030,0,1};DECK032;Goats 1;run;.;12;0;;static;ordered;A003,A003,A004,A004,A005,A005,S023,A021;{A003,0,1},{A004,0,1},{A005,0,1},{S023,0,1},{S030,0,1};DECK033;Inpsiring Wolf 1;run;.;16;0;;static;ordered;A029,A002,A003,A004,A011,A022,A027,A014,S021,S022,S030,A021,A018,A021;{S021,0,1},{S022,0,1},{S030,0,1},{A002,0,1},{A003,0,1},{A004,0,1},{A011,0,1},{A022,0,1},{A027,0,1},{A014,0,1},{A021,0,1},{A018,0,1};DECK034;Crass Babboon 1;run;.;16;0;;static;ordered;A020,A021,A005,A006,A007,A012,A017,A018,A019,A026,A025,S004,S004,A021;{S004,0,1},{A021,0,1},{A005,0,1},{A006,0,1},{A007,0,1},{A012,0,1},{A017,0,1},{A018,0,1},{A019,0,1},{A026,0,1},{A025,0,1};DECK035;Opinionated Cow 1;run;.;12;0;;static;ordered;A021,A021,A004,A018,A019,A023,A026,H000,H000,A017,H022,H011,H004,A020;{A021,1,2},{A004,0,1},{A018,0,1},{A019,0,1},{A023,0,1},{A026,0,1},{H000,0,1},{A017,0,1},{H022,0,1},{H011,0,1},{H004,0,1},{A020,0,1};DECK036;Stealing Giraffes 1;run;.;24;0;;static;ordered;A025,A025,A024,A024,A019,A019,A018,A018,A021,S029,S004;{A025,0,1},{A024,0,1},{A019,0,1},{A018,0,1},{A021,0,1},{S029,0,1},{S004,0,1};DECK037;Bundle of Snakes 1;run;.;16;0;;static;ordered;A008,A009,A009,A009,A010,A010,A010,S030,S017,A021,S018,A008,A009;{A009,0,1},{A010,0,1};DECK038;King of Mooses;run;.;24;0;;static;ordered;A016,A015,A015,A015,A014,A014,A014,A012,A006,A007,A021,A023,A004,A013,A022,A022,A022,S028;;DECK039;Village Bullies;run;.;12;0;;static;ordered;A021,H000,H001,H001,H001,H003,H004,H001,H000,H010,S022,S022;;DECK040;Village Militia;run;.;12;0;;static;ordered;H000,H000,H000,H002,H002,H002,H005,H002,H002,H002,S003,S030,H015;;DECK041;Summoning Startup 1;run;.;12;0;;static;ordered;S015,S016,S015,S016,U002,U002,U004,U004,U005,U005,U001,U000;{S015,0,1},{S016,0,1},{U002,0,1},{U004,0,1},{U005,0,1},{U001,0,1},{U000,0,1},{S023,0,1};DECK042;Lesser Evil 1;run;.;12;0;;static;ordered;U000,U000,U001,U001,U002,U011,S031,S000,U003,U006,U022,S023;{U002,0,1},{U004,0,1},{U005,0,1},{U001,0,1},{U000,0,0};DECK043;Kingshand;run;.;24;0;;static;ordered;H020,H017,H017,H017,H016,H012,H012,H012,H009,H009,H009,H009,S029,S029,S005,H011,S026,S028,H023,H023;{H017,0,1},{H009,0,1},{H012,0,1},{H018,0,1};DECK044;Healing Circle;run;.;16;0;;static;ordered;H005,H009,H009,H011,H011,H015,H016,H016,H016,H023,H023,H013,S003,S003,S005,S005;{S003,0,1},{S005,0,1},{H005,0,1},{H009,0,1},{H015,0,1},{H016,0,1},{H023,0,1},{H013,0,1};DECK045;Forest Bandits;run;.;16;0;;static;ordered;H001,H001,H002,H002,H003,H003,H003,H006,H007,H008,H022,H022,H022,H015,A003,A002;;DECK046;Assasins Credo;run;.;16;0;;static;ordered;H013,H013,A007,A008,A009,A003,A018,H009,H009,H011,H022,H023,S006,S006,S029,S029;;DECK047;VAMPIRES;run;.;16;0;;static;ordered;U012,U012,U012,A027,A027,A028,A028,U011,U011,U011,U000,U000,U022,U000,S023,S018,S018,S030;;DECK048;Demon Lords Fun Pit;run;.;24;0;;static;ordered;U008,U008,U019,U018,U014,U013,U010,U010,U009,U009,U007,U006,U006,U006,U003,U003,U003,U001,U001,U001,S002,S002,S030,U022,S030;;DECK049;Bandit Ringleader;run;;24;0;;static;ordered;H014,H014,H014,H019,H023,H023,H023,H022,H022,H012,H012,H010,H010,H008,H003,H003,H003,H015;;DECK050;All kinds of Rangers;run;;16;0;;static;ordered;H023,H023,H023,H023,H022,H022,H022,H022,H009,H009,H009,H009;;DECK051;Lots of Imps;run;;24;0;;static;ordered;U010,U010,U010,U010,U010,U010,U010,U010,U010,U010,U010,U010,U009,S023;;DECK052;Grand Magggus Deck;run;;30;0;;static;ordered;S032,U022,U022,S031,S030,S030,S029,S025,S025,S022,S022,S015,S015,S016,S016,S012,S024,S024,S011,S011,S002,S002,S002,S002,S001,S000,S000,S000,S000,S000,S023;;DECK053;Anti Magggus Deck;run;;30;0;;static;ordered;S033,U024,U024,U023,U023,U023,U023,U023,H016,H016,H015,H015,H005,H005,H009,H009,H009,H011,H011,H013,H013,H012,H012,H012,H022,H022,H022,H022,H022,H022;;DECK054;Total Summoner;run;;30;0;;static;ordered;U002,U002,U004,U004,U005,U005,U015,U015,U020,S015,S016,S000,S001,S000,S015,S016,U020,U021,S012,S012;;DECK055;Bats Bats Bats Bats Bats;run;;14;0;;static;ordered;A027,A027,A027,A027,A027,A027,A027,A027,A027,A027,A027,A027,A027,A027,A027,A027,A027,A027,A027,A027,;;" end particle_nums_maxVal=1 particle_nums_size=1000 particle_nums_index=1 particle_random_floats = {} particle_random_ints = {} particle_systems = {} function init_particles() particle_random_ints={} particle_random_floats={} for i = 1, particle_nums_size, 1 do table.insert(particle_random_ints,math.random(particle_nums_maxVal)) table.insert(particle_random_floats,math.random()) end end function get_random_float_particle() local val=particle_random_floats[particle_nums_index] particle_nums_index=math.max(1,(particle_nums_index+1)%particle_nums_size) return val end function get_random_num_particle(maxVal) local maxVal=math.max(2,maxVal or particle_nums_maxVal) local val=particle_random_ints[particle_nums_index]%(maxVal-1) particle_nums_index=math.max(1,(particle_nums_index+1)%particle_nums_size) val=val+1 return val end function make_psystem(minlife, maxlife, minstartsize, maxstartsize, minendsize, maxendsize) local ps = { autoremove = true, minlife = minlife, maxlife = maxlife, minstartsize = minstartsize, maxstartsize = maxstartsize, minendsize = minendsize, maxendsize = maxendsize, particles = {}, emittimers = {}, emitters = {}, drawfuncs = {}, affectors = {}, } table.insert(particle_systems, ps) return ps end function update_psystems(everyOtherTurn) local timenow = time() for key,ps in pairs(particle_systems) do update_ps(ps, timenow, everyOtherTurn) end end function update_ps(ps, timenow, everyOtherTurn) for key,et in pairs(ps.emittimers) do local keep = et.timerfunc(ps, et.params) if (keep==false) then table.remove(ps.emittimers, key) end end for key,p in pairs(ps.particles) do p.phase = (timenow-p.starttime)/(p.deathtime-p.starttime) for key,a in pairs(ps.affectors) do a.affectfunc(p, a.params) end if everyOtherTurn then p.x = p.x + (p.vx*2) p.y = p.y + (p.vy*2) else p.x = p.x + p.vx p.y = p.y + p.vy end local dead = false if (p.x<0 or p.x>240 or p.y<0 or p.y>136) then dead = true end if (timenow>=p.deathtime) then dead = true end if (dead==true) then table.remove(ps.particles, key) end end if (ps.autoremove==true and #ps.particles<=0) then local psidx = -1 for pskey,pps in pairs(particle_systems) do if pps==ps then table.remove(particle_systems, pskey) return end end end end function draw_ps(ps, params) for key,df in pairs(ps.drawfuncs) do df.drawfunc(ps, df.params) end end function draw_psystems() for key,ps in pairs(particle_systems) do draw_ps(ps) end end function emit_particle(psystem) local p = {} local ecount = nil local e = psystem.emitters[get_random_num_particle(#psystem.emitters)] e.emitfunc(p, e.params) p.phase = 0 p.starttime = time() p.deathtime = time()+frnd(psystem.maxlife-psystem.minlife)+psystem.minlife p.startsize = frnd(psystem.maxstartsize-psystem.minstartsize)+psystem.minstartsize p.endsize = frnd(psystem.maxendsize-psystem.minendsize)+psystem.minendsize table.insert(psystem.particles, p) end function frnd(max) return get_random_float_particle()*max end function emittimer_burst(ps, params) for i=1,params.num do emit_particle(ps) end return false end function emittimer_constant(ps, params) if (params.nextemittime<=time()) then emit_particle(ps) params.nextemittime = params.nextemittime + params.speed end return true end function emitter_point(p, params) p.x = params.x p.y = params.y p.vx = frnd(params.maxstartvx-params.minstartvx)+params.minstartvx p.vy = frnd(params.maxstartvy-params.minstartvy)+params.minstartvy end function emitter_box(p, params) p.x = frnd(params.maxx-params.minx)+params.minx p.y = frnd(params.maxy-params.miny)+params.miny p.vx = frnd(params.maxstartvx-params.minstartvx)+params.minstartvx p.vy = frnd(params.maxstartvy-params.minstartvy)+params.minstartvy end function affect_force(p, params) p.vx = p.vx + params.fx p.vy = p.vy + params.fy end function affect_forcezone(p, params) if (p.x>=params.zoneminx and p.x<=params.zonemaxx and p.y>=params.zoneminy and p.y<=params.zonemaxy) then p.vx = p.vx + params.fx p.vy = p.vy + params.fy end end function affect_stopzone(p, params) if (p.x>=params.zoneminx and p.x<=params.zonemaxx and p.y>=params.zoneminy and p.y<=params.zonemaxy) then p.vx = 0 p.vy = 0 end end function affect_bouncezone(p, params) if (p.x>=params.zoneminx and p.x<=params.zonemaxx and p.y>=params.zoneminy and p.y<=params.zonemaxy) then p.vx = -p.vx*params.damping p.vy = -p.vy*params.damping end end function affect_attract(p, params) if (math.abs(p.x-params.x)+math.abs(p.y-params.y)#params.frames) then params.currframe = 1 end for key,p in pairs(ps.particles) do spr(params.frames[math.floor(params.currframe+p.startsize)%#params.frames],p.x,p.y,0) end end function draw_ps_agespr(ps, params) for key,p in pairs(ps.particles) do local f = math.floor(p.phase*#params.frames)+1 spr(params.frames[f],p.x,p.y,0) end end function draw_ps_rndspr(ps, params) for key,p in pairs(ps.particles) do spr(params.frames[math.floor(p.startsize)],p.x,p.y,0) end end function make_bubbles_ps() local ps = make_psystem(500,3000, 1,9,0.5,0.5) ps.autoremove = false table.insert(ps.emittimers, { timerfunc = emittimer_constant, params = {nextemittime = time(), speed = 0.2} } ) table.insert(ps.emitters, { emitfunc = emitter_box, params = { minx = 0, maxx = 240, miny = 100, maxy= 110, minstartvx = 0, maxstartvx = 0, minstartvy = -1.50, maxstartvy=-0.2 } } ) table.insert(ps.drawfuncs, { drawfunc = draw_ps_agespr, params = { frames = {16,16,17,17,17,18,18,18,18,18,18,18,18,18,18,19} } } ) table.insert(ps.affectors, { affectfunc = affect_orbit, params = { phase = 0, speed = 0.001, xstrength = 0.5, ystrength = 0 } } ) end function make_healBubbles_ps(startX,startY,timeMult) local ps = make_psystem(600+(2-timeMult)*100,800+(2-timeMult)*120,3,5,0.5,0.5) ps.autoremove = false table.insert(ps.emittimers, { timerfunc = emittimer_burst, params = { num = 10} } ) table.insert(ps.emitters, { emitfunc = emitter_box, params = { minx = startX-20, maxx = startX+20, miny = startY-10, maxy= startY, minstartvx = 0, maxstartvx = 0, minstartvy = -1.5, maxstartvy=-0.5 } } ) table.insert(ps.drawfuncs, { drawfunc = draw_ps_agespr, params = { frames = {276,276,276,276,276,257,257,257,257,257,257,257} } } ) table.insert(ps.affectors, { affectfunc = affect_orbit, params = { phase = 0, speed = 0.001, xstrength = 0.5, ystrength = 0 } } ) end function make_buffCutBubbles_ps(ex,ey,timeMult,startSpr,endSpr) local ps = make_psystem(600+(2-timeMult)*100,800+(2-timeMult)*125,3,5,0.5,0.5) ps.autoremove = false table.insert(ps.emittimers, { timerfunc = emittimer_burst, params = { num = 10} } ) table.insert(ps.emitters, { emitfunc = emitter_box, params = { minx = ex-20, maxx = ex+20, miny = ey-10, maxy= ey, minstartvx = 0, maxstartvx = 0, minstartvy = ((eyx2 or eyy2) then table.insert(ps.affectors, { affectfunc = affect_stopzone, params = { zoneminx = x, zonemaxx = x2, zoneminy = y, zonemaxy = y2 } }) end end) foreach(GUIHelper.enemyBattlefieldCards,function(cardGUI) local x=cardGUI.origX local y=cardGUI.origY local x2=x+cardGUI.w local y2=y+cardGUI.h if cardGUI.cardObj and (exx2 or eyy2) then table.insert(ps.affectors, { affectfunc = affect_stopzone, params = { zoneminx = x, zonemaxx = x2, zoneminy = y, zonemaxy = y2 } }) end end) local cardGUI=GUIHelper.playerLeaderCard if (excardGUI:getRightX() or eycardGUI:getDownY()) then table.insert(ps.affectors, { affectfunc = affect_stopzone, params = { zoneminx = cardGUI.x, zonemaxx = cardGUI:getRightX(), zoneminy = cardGUI.y, zonemaxy = cardGUI:getDownY() } }) end cardGUI=GUIHelper.enemyLeaderCard if (excardGUI:getRightX() or eycardGUI:getDownY()) then table.insert(ps.affectors, { affectfunc = affect_stopzone, params = { zoneminx = cardGUI.x, zonemaxx = cardGUI:getRightX(), zoneminy = cardGUI.y, zonemaxy = cardGUI:getDownY() } }) end end function make_mouse_spell_interacted_with_gui_ps(ex,ey,timeMult) local ps = make_psystem((2-timeMult)*30,250+(2-timeMult)*80, 1,1, 0.5,0.5) table.insert(ps.emittimers, { timerfunc = emittimer_burst, params = { num = 15} } ) table.insert(ps.emitters, { emitfunc = emitter_point, params = { x = ex, y = ey, minstartvx = -1, maxstartvx = 1, minstartvy = -2.5, maxstartvy=2.5 } } ) table.insert(ps.drawfuncs, { drawfunc = draw_ps_pixel, params = { colors = {15,14,12,9,4,3} } } ) table.insert(ps.affectors, { affectfunc = affect_force, params = { fx = 0, fy = 0.1 } } ) end function make_mouse_spell_interacted_basic_ps(ex,ey,timeMult) local ps = make_psystem((2-timeMult)*30,125+(2-timeMult)*80, 1,1, 0.5,0.5) table.insert(ps.emittimers, { timerfunc = emittimer_burst, params = { num = 2 } } ) table.insert(ps.emitters, { emitfunc = emitter_point, params = { x = ex, y = ey, minstartvx = -0.1, maxstartvx = 0.1, minstartvy = -0.1, maxstartvy=0.1 } } ) table.insert(ps.drawfuncs, { drawfunc = draw_ps_pixel, params = { colors = {15,14,12,9,4,3} } } ) table.insert(ps.affectors, { affectfunc = affect_force, params = { fx = 0.1, fy = 0.1 } } ) end function make_mouse_spell_no_interaction_ps(ex,ey,timeMult) local ps = make_psystem((2-timeMult)*30,175+(2-timeMult)*80, 1,1, 0.5,0.5) table.insert(ps.emittimers, { timerfunc = emittimer_burst, params = { num = 5 } } ) table.insert(ps.emitters, { emitfunc = emitter_point, params = { x = ex, y = ey, minstartvx = -0.1, maxstartvx = 0.1, minstartvy = 0, maxstartvy=1.5 } } ) table.insert(ps.drawfuncs, { drawfunc = draw_ps_fillcirc, params = { colors = {15,14,12,9,4,3} } } ) table.insert(ps.affectors, { affectfunc = affect_force, params = { fx = 0.15, fy = 0.15 } } ) end function make_mana_sparks_gain_ps(ex,ey,timeMult) make_quick_smoke_ps(ex,ey,timeMult,{15,13,15,8,13,8,1,8,1}) end function make_mana_sparks_spend_ps(ex,ey,timeMult) local ps = make_psystem(300+(2-timeMult)*30,700+(2-timeMult)*80, 1,2, 0.5,0.5) local f=0.15 local x=0 local y=((ey