okey.erl 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. -module(okey).
  2. -compile(export_all).
  3. -include_lib("n2o/include/wf.hrl").
  4. -include("../../server/include/requests.hrl").
  5. -include("../../server/include/settings.hrl").
  6. -include_lib("avz/include/avz.hrl").
  7. -include_lib("kvs/include/user.hrl").
  8. -define(GAMEID, 1000001).
  9. %-define(GAMEID, 5000220).
  10. -record(player, {id, label, info, take, discard, history = []}).
  11. -define(RESET_ELEMENTS, [
  12. {gosterge, #label{ id = gosterge, body="Gosterge: "}},
  13. {h1, #dropdown{ id = h1, options = []}},
  14. {h2, #dropdown{ id = h2, options = []}},
  15. {h3, #dropdown{ id = h3, options = []}},
  16. {h4, #dropdown{ id = h4, options = []}} ]).
  17. user() ->
  18. case wf:user() of undefined ->
  19. Imagionary = fake_users:imagionary_users(),
  20. {Id,Name,Surname} = lists:nth(crypto:rand_uniform(1,length(Imagionary)),Imagionary),
  21. X = #user{id = fake_users:fake_id(Id),names = Name,surnames = Surname},
  22. wf:user(X), X; U-> U end.
  23. color(Id,Color) -> wf:wire(wf:f("document.querySelector('#~s').style.color = \"~s\";",[Id,Color])).
  24. unselect(Id) -> color(Id,black).
  25. select(Id) -> color(Id,red).
  26. redraw_istaka(TilesList) ->
  27. redraw_tiles(TilesList, #dropdown{id = istaka, postback = combo, source = [istaka]}).
  28. redraw_tiles(undefined, _DropDown) -> [];
  29. redraw_tiles([] = _TilesList, DropDown = #dropdown{id = ElementId}) ->
  30. wf:update(ElementId, [DropDown#dropdown{value = [], options = []}]);
  31. redraw_tiles([{Tile, _}| _ ] = TilesList, DropDown = #dropdown{id = ElementId}) ->
  32. wf:update(ElementId, [DropDown#dropdown{value = Tile, options = [#option{label = CVBin, value = CVBin} || {CVBin, _} <- TilesList]}]).
  33. redraw_players(Players) ->
  34. User = user(),
  35. [ begin PN = player_name(PI),
  36. wf:update(LabelId, #label{ id = LabelId,
  37. style= case User#user.id == Id of
  38. true -> "font-weight: bold;";
  39. _ -> "" end, body = <<" ",PN/binary," ">>})
  40. end || #player{label = LabelId, info = #'PlayerInfo'{id = Id} = PI} <- Players].
  41. update_players(UpdatedPlayer = #player{label = LabelId}, Players) ->
  42. lists:sort(
  43. fun(#player{label = E1}, #player{label = E2}) -> E1 < E2 end,
  44. [UpdatedPlayer | lists:keydelete(LabelId, #player.label, Players)]
  45. ).
  46. player_name(PI) -> auth_server:player_name(PI).
  47. tash(C,V) -> {wf:to_binary([wf:to_list(C)," ",wf:to_list(V)]), {C, V}}.
  48. main() -> #dtl{file="index", bindings=[{title,<<"N2O">>},{body,body()}]}.
  49. body() ->
  50. wf:wire(#api{name=plusLogin, tag=plus}),
  51. [ #panel { id = history },
  52. #button { id = pluslogin, body = "Login", postback = login_button },
  53. #label { id = nothing, body = " Google"}, #br{}, #br{},
  54. #label { id = gosterge, body = "Gosterge"}, #br{},
  55. #label { id = player1, body = "Seat 1"}, #dropdown{id=h1,options=[]}, #br{},
  56. #label { id = player2, body = "Seat 2"}, #dropdown{id=h2,options=[]}, #br{},
  57. #label { id = player3, body = "Seat 3"}, #dropdown{id=h3,options=[]}, #br{},
  58. #label { id = player4, body = "Seat 4"}, #dropdown{id=h4,options=[]}, #br{}, #br{},
  59. #button { id = attach, body = "Attach", postback = attach },
  60. #button { id = join, body = "Join", postback = join, source = [games_ids]},
  61. #dropdown { id = games_ids, postback = combo, options = []}, #br{},
  62. #dropdown { id = take_src, options = [
  63. #option{label="Table",value="0"},
  64. #option{label="Left",value="1"}]},
  65. #button { id = take, body = "Take", postback = take, source=[take_src]},
  66. #dropdown { id = istaka, postback = combo, source=[istaka],options=[]},
  67. #button { id = discard, body = "Discard", postback = discard, source=[istaka]},
  68. #button { id = reveal, body = "Reveal", postback = reveal, source=[istaka]}, #br{},
  69. #button { id = saw_okey, body = "I Saw Okey", postback = i_saw_okey},
  70. #button { id = have_8, body = "8 Tashes", postback = i_have_8_tashes},
  71. #button { id = pause, body = "Pause", postback = pause},
  72. #button { id = info, body = "PlayerInfo", postback = player_info} ].
  73. event(terminate) -> wf:info("terminate");
  74. event(init) ->
  75. GamesIds =
  76. case game_manager:get_all_games_ids() of
  77. [] ->
  78. [?GAMEID];
  79. List ->
  80. List
  81. end,
  82. wf:update(games_ids,
  83. [
  84. #dropdown{id = games_ids, value = ?GAMEID, options =
  85. [#option{label = wf:to_list(GameId), value = wf:to_list(GameId)} || GameId <- GamesIds]
  86. }
  87. ]
  88. ),
  89. event(attach),
  90. event(join);
  91. event(login_button) -> wf:wire(protocol:logout());
  92. event(join) ->
  93. GameId = get(okey_game_id),
  94. wf:wire(protocol:join(wf:to_list(GameId)));
  95. event(take) ->
  96. GameId = get(okey_game_id),
  97. wf:wire(protocol:take(wf:to_list(GameId), wf:q(take_src)));
  98. event(player_info) ->
  99. User = user(),
  100. wf:wire(protocol:player_info(
  101. wf:f("'~s'",[wf:to_list(User#user.id)]),wf:f("'~s'",[game_okey])));
  102. event(attach) ->
  103. {ok,GamePid} = game_session:start_link(self()),
  104. wf:session(<<"game_pid">>,GamePid),
  105. User = user(),
  106. put(okey_im, User#user.id),
  107. wf:wire(wf:f("document.user = '~s';",[User#user.id])),
  108. wf:info("Session User: ~p",[User]),
  109. GameId = case wf:q(games_ids) of undefined -> ?GAMEID; Res -> Res end,
  110. put(okey_game_id, GameId),
  111. Token = auth_server:generate_token(GameId,User),
  112. wf:wire(protocol:attach(wf:f("'~s'",[Token]))),
  113. ok;
  114. event(discard) ->
  115. TilesList = get(game_okey_tiles),
  116. DiscardCombo = wf:q(istaka),
  117. GameId = get(okey_game_id),
  118. case lists:keyfind(erlang:list_to_binary(DiscardCombo), 1, TilesList) of
  119. {_, {C, V}} ->
  120. wf:wire(protocol:discard(wf:to_list(GameId), wf:to_list(C), wf:to_list(V)));
  121. false -> wf:info("Discard Combo: ~p",[DiscardCombo]) end;
  122. event(reveal) ->
  123. TilesList = case get(game_okey_tiles) of undefined -> []; T -> T end,
  124. Discarded = wf:q(istaka),
  125. GameId = get(okey_game_id),
  126. case lists:keyfind(wf:to_binary(Discarded), 1, TilesList) of
  127. {_, {CD, VD} = Key} ->
  128. Hand = [{C,V} || {_, {C, V}} <- lists:keydelete(Key, 2, TilesList) ],
  129. HandJS = "[[" ++ string:join([
  130. wf:f("tuple(atom('OkeyPiece'),~p,~p)",[C,V]) || {C,V} <- Hand],",") ++ "],[]]",
  131. RevealJS = protocol:reveal(wf:to_list(GameId),wf:f("~p",[CD]),wf:f("~p",[VD]),HandJS),
  132. wf:info("RevealJS: ~p",[lists:flatten(RevealJS)]),
  133. wf:wire(RevealJS);
  134. _ ->
  135. wf:info("error discarded ~p", Discarded)
  136. end;
  137. event(i_saw_okey) ->
  138. wf:info("i_saw_okey!"),
  139. GameId = get(okey_game_id),
  140. wf:wire(protocol:i_saw_okey(wf:to_list(GameId)));
  141. event(i_have_8_tashes) ->
  142. wf:info("i_gave_8_tashes!"),
  143. GameId = get(okey_game_id),
  144. wf:wire(protocol:i_have_8_tashes(wf:to_list(GameId)));
  145. event(pause) ->
  146. Action =
  147. case get(game_okey_pause) of
  148. X when X == resume orelse X == undefined ->
  149. put(game_okey_pause, pause),
  150. wf:update(pause, [#button{id = pause, body = "Resume", postback = pause}]),
  151. "pause";
  152. pause ->
  153. put(game_okey_pause, resume),
  154. wf:update(pause, [#button{id = pause, body = <<"Pause">>, postback = pause}]),
  155. "resume"
  156. end,
  157. GameId = get(okey_game_id),
  158. wf:wire(protocol:pause(wf:to_list(GameId), wf:f("~p", [Action])));
  159. %event({binary,M}) -> {ok,<<"Hello">>};
  160. event({client,Message}) ->
  161. wf:info("Client: ~p", [Message]),
  162. case wf:session(<<"game_pid">>) of
  163. undefined -> skip;
  164. GamePid -> SyncRes = game_session:process_request(GamePid, Message),
  165. wf:info("Sync Result: ~p",[SyncRes]) end;
  166. event({server, {game_event, _, okey_game_started, Args}}) ->
  167. wf:info("Game Started: ~p", [Args]),
  168. {_, Tiles} = lists:keyfind(tiles, 1, Args),
  169. TilesList = [tash(C, V) || {_, C, V} <- Tiles],
  170. case lists:keyfind(gosterge, 1, Args) of
  171. {_, {_, C, V}} ->
  172. wf:update(gosterge, #label{id = gosterge, body = wf:to_binary(["Gosterge: ", wf:to_list(C), " ", wf:to_list(V)])});
  173. _ ->
  174. ok
  175. end,
  176. put(game_okey_tiles, TilesList),
  177. put(game_okey_pause, resume),
  178. redraw_istaka(TilesList);
  179. event({server, {game_event, _, okey_game_player_state, Args}}) ->
  180. wf:info("Player State: ~p", [Args]),
  181. case lists:keyfind(whos_move, 1, Args) of
  182. {_, null} -> ok;
  183. {_, WhosMove} ->
  184. Players = get(okey_players),
  185. #player{label = X} = lists:keyfind(WhosMove, #player.id, Players),
  186. case X of
  187. null -> skip;
  188. false -> skip;
  189. X -> select(X), put(okey_turn_mark,X) end,
  190. {_, Tiles} = lists:keyfind(tiles, 1, Args),
  191. TilesList = [tash(C, V)|| {_, C, V} <- Tiles],
  192. redraw_istaka(TilesList),
  193. put(game_okey_tiles, TilesList),
  194. {_, Piles} = lists:keyfind(piles, 1, Args),
  195. UpdatedPlayers = [ begin
  196. Player = #player{discard = RightPileComboId}
  197. = lists:keyfind(PlayerId, #player.id, Players),
  198. ConvertedPile = [ tash(C, V) || {_, C, V} <- Pile],
  199. redraw_tiles(ConvertedPile, #dropdown{id = RightPileComboId}),
  200. Player#player{history = ConvertedPile}
  201. end || {PlayerId, Pile} <- Piles ],
  202. put(okey_players, lists:sort(fun(#player{label = E1}, #player{label = E2}) ->
  203. E1 < E2 end, UpdatedPlayers));
  204. _ -> ok end;
  205. event({server, {game_event, _, okey_tile_taken, Args}}) ->
  206. wf:info("Taken: ~p", [Args]),
  207. Im = get(okey_im),
  208. {_, PlayerId} = lists:keyfind(player, 1, Args),
  209. case lists:keyfind(revealed, 1, Args) of
  210. {_, {_, C, V}} ->
  211. if Im == PlayerId ->
  212. TilesList = [ tash(C, V) | get(game_okey_tiles)],
  213. %%wf:info("Tiles: ~p",[TilesList]),
  214. put(game_okey_tiles, TilesList),
  215. redraw_istaka(TilesList);
  216. true -> ok end,
  217. case lists:keyfind(pile, 1, Args) of
  218. {_, 1} -> %% have taken from left
  219. Players = get(okey_players),
  220. #player{take=From} = lists:keyfind(PlayerId,#player.id,Players),
  221. LeftPlayer = #player{discard=Combo,history=DiscardHistory}
  222. = lists:keyfind(From,#player.label,Players),
  223. History = lists:keydelete({C, V}, 2, DiscardHistory),
  224. redraw_tiles(History, #dropdown{id=Combo}),
  225. put(okey_players,update_players(LeftPlayer#player{history=History},Players));
  226. _ -> ok end;
  227. _ -> ok end;
  228. event({server, {game_event, _, okey_tile_discarded, Args}}) ->
  229. wf:info("Discarded: ~p", [Args]),
  230. Im = get(okey_im),
  231. {_, PlayerId} = lists:keyfind(player, 1, Args),
  232. {_, {_, C, V}} = lists:keyfind(tile, 1, Args),
  233. if Im == PlayerId ->
  234. TilesListOld = get(game_okey_tiles),
  235. TilesList = lists:keydelete({C, V}, 2, TilesListOld),
  236. put(game_okey_tiles, TilesList),
  237. redraw_istaka(TilesList);
  238. true -> ok end,
  239. Players = get(okey_players),
  240. Player = #player{discard = RightPileComboId, history = OldRightPile}
  241. = lists:keyfind(PlayerId, #player.id, Players),
  242. NewRightPile = [ tash(C, V) | OldRightPile],
  243. redraw_tiles(NewRightPile, #dropdown{id = RightPileComboId}),
  244. UpdatedPlayer = Player#player{history = NewRightPile},
  245. UpdatedPlayers = update_players(UpdatedPlayer, Players),
  246. put(okey_players, UpdatedPlayers);
  247. event({server,{game_event, _Game, okey_turn_timeout, Args}}) ->
  248. wf:info("Turn Timeout: ~p", [Args]);
  249. event({server, {game_event, _, okey_game_info, Args}}) ->
  250. wf:info("Game Info: ~p", [Args]),
  251. {_, PlayersInfo} = lists:keyfind(players, 1, Args),
  252. [wf:update(ElementId, [Element]) || {ElementId, Element} <- ?RESET_ELEMENTS],
  253. PlayersTempl = [
  254. #player{label = player1, discard = h1, take = player4},
  255. #player{label = player2, discard = h2, take = player1},
  256. #player{label = player3, discard = h3, take = player2},
  257. #player{label = player4, discard = h4, take = player3}],
  258. Players = lists:zipwith(fun(Players, #'PlayerInfo'{id = Id} = PI) ->
  259. Players#player{id=Id,info=PI} end, PlayersTempl, PlayersInfo),
  260. put(okey_players, Players),
  261. redraw_players(Players);
  262. event({server,{game_event, _, player_left, Args}}) ->
  263. wf:info("Player Left: ~p", [Args]),
  264. {_, OldPlayerId} = lists:keyfind(player, 1, Args),
  265. {_, PI} = lists:keyfind(replacement, 1, Args),
  266. #'PlayerInfo'{id = NewPlayerId} = PI,
  267. OldPlayers = get(okey_players),
  268. OldPlayer = lists:keyfind(OldPlayerId, #player.id, OldPlayers),
  269. NewPlayers = update_players(OldPlayer#player{id=NewPlayerId,info=PI}, OldPlayers),
  270. put(okey_players, NewPlayers),
  271. redraw_players(NewPlayers),
  272. case get(okey_turn_mark) of undefined -> ok; X -> select(X) end;
  273. event({server,{game_event, _, okey_next_turn, Args}}) ->
  274. wf:info("Next Turn: ~p", [Args]),
  275. {player, PlayerId} = lists:keyfind(player, 1, Args),
  276. #player{label = LabelId} = lists:keyfind(PlayerId, #player.id, get(okey_players)),
  277. case get(okey_turn_mark) of
  278. undefined -> ok;
  279. OldLabelId -> unselect(OldLabelId) end,
  280. select(LabelId),
  281. put(okey_turn_mark, LabelId);
  282. event({register,User}) -> wf:info("Register: ~p",[User]), kvs:add(User), wf:user(User);
  283. event({login,User}) -> wf:info("Login: ~p",[User]), kvs:put(User), wf:user(User), event(init);
  284. event(_Event) -> wf:info("Event: ~p", [_Event]).
  285. api_event(X,Y,Z) -> avz:api_event(X,Y,Z).