okey.erl 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. -module(okey).
  2. -compile(export_all).
  3. -include_lib("n2o/include/wf.hrl").
  4. -include_lib("server/include/requests.hrl").
  5. -include_lib("server/include/settings.hrl").
  6. -include_lib("avz/include/avz.hrl").
  7. -include_lib("kvs/include/user.hrl").
  8. -define(GAMEID, game_form()).
  9. game_form() ->
  10. case wf:qs(<<"game">>) of
  11. undefined -> 1000001;
  12. X -> wf:to_integer(X) end.
  13. -record(player, {id, label, info, take, discard, history = []}).
  14. -define(RESET_ELEMENTS, [
  15. {gosterge, #label{ id = gosterge, body="Gosterge: "}},
  16. {h1, #dropdown{ id = h1, options = []}},
  17. {h2, #dropdown{ id = h2, options = []}},
  18. {h3, #dropdown{ id = h3, options = []}},
  19. {h4, #dropdown{ id = h4, options = []}} ]).
  20. new_user() ->
  21. Imagionary = anonymous:imagionary_users(),
  22. {Id,Name,Surname} = lists:nth(crypto:rand_uniform(1,length(Imagionary)),Imagionary),
  23. FakeId = anonymous:fake_id(Id),
  24. X = #user{
  25. id = FakeId,
  26. tokens=[{n2o,get(session_id)}],
  27. names = Name,
  28. surnames = Surname},
  29. wf:wire(wf:f("document.cookie='~s=~s; path=/; expires=~s';",
  30. ["n2o-name",wf:to_list(FakeId),js_session:cookie_expire(js_session:ttl())])),
  31. kvs:put(X),
  32. X.
  33. user() ->
  34. case wf:user() of
  35. undefined ->
  36. SessionUser = wf:cookie_req(<<"n2o-name">>,?REQ),
  37. SessionId = get(session_id),
  38. wf:info(?MODULE,"Auth User: ~p",[SessionUser]),
  39. wf:info(?MODULE,"Auth Id: ~p",[SessionId]),
  40. X = case kvs:get(user,SessionUser) of
  41. {ok,User} ->
  42. SS = lists:keyfind(n2o,1,User#user.tokens),
  43. case SS of
  44. {n2o,SessionId} -> User;
  45. _ -> new_user() end;
  46. _ -> new_user() end,
  47. wf:user(X),
  48. X;
  49. U-> U end.
  50. color(Id,Color) -> ok. % wf:wire(wf:f("document.querySelector('#~s').style.color = \"~s\";",[Id,Color])).
  51. unselect(Id) -> color(Id,black).
  52. select(Id) -> color(Id,red).
  53. update(A,B) -> ok. % wf:update(A,B);
  54. redraw_istaka(TilesList) ->
  55. redraw_tiles(TilesList, #dropdown{id = "istaka", postback = combo, source = [istaka]}).
  56. redraw_tiles(undefined, _DropDown) -> [];
  57. redraw_tiles([] = _TilesList, DropDown = #dropdown{id = ElementId}) ->
  58. okey:update(ElementId, [DropDown#dropdown{value = [], options = []}]);
  59. redraw_tiles([{Tile, _}| _ ] = TilesList, DropDown = #dropdown{id = ElementId}) ->
  60. okey:update(ElementId, [DropDown#dropdown{value = Tile,
  61. options = [#option{label = CVBin, value = CVBin} || {CVBin, _} <- TilesList]}]).
  62. redraw_players(Players) ->
  63. User = user(),
  64. [ begin PN = player_name(PI),
  65. okey:update(LabelId, #label{ id = LabelId,
  66. style= case User#user.id == Id of
  67. true -> "font-weight: bold;";
  68. _ -> "" end, body = <<" ",PN/binary," ">>})
  69. end || #player{label = LabelId, info = #'PlayerInfo'{id = Id} = PI} <- Players].
  70. update_players(UpdatedPlayer = #player{label = LabelId}, Players) ->
  71. lists:sort(
  72. fun(#player{label = E1}, #player{label = E2}) -> E1 < E2 end,
  73. [UpdatedPlayer | lists:keydelete(LabelId, #player.label, Players)]
  74. ).
  75. player_name(PI) -> auth_server:player_name(PI).
  76. tash(C,V) -> {wf:to_binary([wf:to_list(C)," ",wf:to_list(V)]), {C, V}}.
  77. main() -> #dtl{file="index", bindings=[{title,<<"N2O">>},{body,body()}]}.
  78. send_roster(Pid) ->
  79. % X = [ send_roster_item(User) || User=#user{tokens=Tokens} <- kvs:all(user), Tokens /= [], Tokens /= undefined],
  80. X = [ {User#user.id,User#user.names,User#user.surnames} || User=#user{tokens=Tokens} <- kvs:all(user), Tokens /= [], Tokens /= undefined],
  81. Lists = split(170,X,[]),
  82. [ send_roster_group(Pid,List) || List <- Lists],
  83. Pid ! {server,{roster_end,length(Lists)}},
  84. wf:info(?MODULE,"Users: ~p",[length(X)]).
  85. split(N,[],Result) -> Result;
  86. split(N,List,Result) when length(List) < N -> Result ++ [List];
  87. split(N,List,Result) -> {A,B}=lists:split(N,List), Result ++ [A] ++ split(N,B,Result).
  88. already_online(Pid) ->
  89. [ Pid ! {user_online,User} || {_,_,{_,User}} <- game:online() ].
  90. send_roster_item(Pid,User) ->
  91. Pid ! {server,{roster_item,User#user.id,User#user.names,User#user.surnames}}.
  92. send_roster_group(Pid,List) ->
  93. wf:info(?MODULE,"User Group: ~p",[List]),
  94. Pid ! {server,{roster_group,List}}.
  95. body() -> [].
  96. body2() ->
  97. wf:wire(#api{name=plusLogin, tag=plus}),
  98. [ #panel { id = history },
  99. #button { id = pluslogin, body = "Login", postback = login_button },
  100. #label { id = nothing, body = " Google"}, #br{}, #br{},
  101. #label { id = gosterge, body = "Gosterge"}, #br{},
  102. #label { id = player1, body = "Seat 1"}, #dropdown{id=h1,options=[]}, #br{},
  103. #label { id = player2, body = "Seat 2"}, #dropdown{id=h2,options=[]}, #br{},
  104. #label { id = player3, body = "Seat 3"}, #dropdown{id=h3,options=[]}, #br{},
  105. #label { id = player4, body = "Seat 4"}, #dropdown{id=h4,options=[]}, #br{}, #br{},
  106. #button { id = logout, body = "Logout", postback = login_button },
  107. #button { id = attach, body = "Attach", postback = attach },
  108. #button { id = join, body = "Join", postback = join, source = [games_ids]},
  109. #dropdown { id = games_ids, postback = combo, options = []}, #br{},
  110. #dropdown { id = take_src, options = [
  111. #option{label="Table",value="0"},
  112. #option{label="Left",value="1"}]},
  113. #button { id = take, body = "Take", postback = take, source=[take_src]},
  114. #dropdown { id = istaka, postback = combo, source=[istaka],options=[]},
  115. #button { id = discard, body = "Discard", postback = discard, source=[istaka]},
  116. #button { id = reveal, body = "Reveal", postback = reveal, source=[istaka]}, #br{},
  117. #button { id = saw_okey, body = "I Saw Okey", postback = i_saw_okey},
  118. #button { id = have_8, body = "8 Tashes", postback = i_have_8_tashes},
  119. #button { id = pause, body = "Pause", postback = pause},
  120. #button { id = info, body = "PlayerInfo", postback = player_info} ].
  121. event(terminate) ->
  122. User = user(),
  123. wf:send(broadcast,{user_offline,User}),
  124. wf:info(?MODULE,"EXTerminate",[]);
  125. event(init) ->
  126. js_session:ensure_sid([],?CTX),
  127. GamesIds = case game:get_all_games_ids() of
  128. [] -> [?GAMEID];
  129. List -> List end,
  130. okey:update(games_ids,#dropdown{id = games_ids, value = ?GAMEID, options =
  131. [#option{label = wf:to_list(GameId), value = wf:to_list(GameId)} || GameId <- GamesIds]}),
  132. wf:info(?MODULE,"Istaka on Started:"),
  133. event(attach),
  134. event(join);
  135. event(login_button) -> wf:wire(protocol:logout());
  136. event(join) ->
  137. GameId = get(okey_game_id),
  138. wf:wire(protocol:join(wf:to_list(GameId)));
  139. event(take) ->
  140. GameId = get(okey_game_id),
  141. wf:wire(protocol:take(wf:to_list(GameId), wf:q(take_src)));
  142. event(player_info) ->
  143. % wf:info(?MODULE,"Cowboy Cookies: ~p",[wf:cookies_req(?REQ)]),
  144. User = user(),
  145. wf:cookie(<<"user">>,<<"macim">>,<<"/ws/">>,24 * 60 * 60),
  146. Wire = protocol:player_info(
  147. wf:f("'~s'",[wf:to_list(User#user.id)]),wf:f("'~s'",[game_okey])),
  148. wf:info(?MODULE,"PlayeInfoJS: ~s",[Wire]),
  149. wf:wire(Wire);
  150. event(attach) ->
  151. {ok,GamePid} = game_session:start_link(self()),
  152. wf:session(<<"game_pid">>,GamePid),
  153. User = user(),
  154. wf:reg(User#user.id),
  155. wf:info(?MODULE,"User Attach: ~p",[User]),
  156. gproc:set_value({p,l,broadcast},{wf:peer(?REQ),User}),
  157. wf:info(?MODULE,"Games Online: ~p",[game:online()]),
  158. put(okey_im, User#user.id),
  159. wf:wire(wf:f("document.user = '~s';document.names = '~s';document.surnames = '~s';",
  160. [User#user.id,User#user.names,User#user.surnames])),
  161. wf:info(?MODULE,"Session User: ~p",[User]),
  162. GameId = case wf:q(games_ids) of undefined -> ?GAMEID; Res -> Res end,
  163. put(okey_game_id, GameId),
  164. Token = auth_server:generate_token(GameId,User),
  165. wf:wire(protocol:attach(wf:f("'~s'",[Token]))),
  166. Pid = self(),
  167. spawn(fun() ->
  168. send_roster(Pid),
  169. already_online(Pid),
  170. wf:send(broadcast,{user_online,User})
  171. end),
  172. ok;
  173. event(discard) ->
  174. TilesList = get(game_okey_tiles),
  175. DiscardCombo = wf:q(istaka),
  176. GameId = get(okey_game_id),
  177. case lists:keyfind(erlang:list_to_binary(DiscardCombo), 1, TilesList) of
  178. {_, {C, V}} ->
  179. wf:wire(protocol:discard(wf:to_list(GameId), wf:to_list(C), wf:to_list(V)));
  180. false -> wf:info(?MODULE,"Discard Combo: ~p",[DiscardCombo]) end;
  181. event(reveal) ->
  182. TilesList = case get(game_okey_tiles) of undefined -> []; T -> T end,
  183. Discarded = wf:q(istaka),
  184. GameId = get(okey_game_id),
  185. case lists:keyfind(wf:to_binary(Discarded), 1, TilesList) of
  186. {_, {CD, VD} = Key} ->
  187. Hand = [{C,V} || {_, {C, V}} <- lists:keydelete(Key, 2, TilesList) ],
  188. HandJS = "[[" ++ string:join([
  189. wf:f("tuple(atom('OkeyPiece'),~p,~p)",[C,V]) || {C,V} <- Hand],",") ++ "],[]]",
  190. RevealJS = protocol:reveal(wf:to_list(GameId),wf:f("~p",[CD]),wf:f("~p",[VD]),HandJS),
  191. wf:info(?MODULE,"RevealJS: ~p",[lists:flatten(RevealJS)]),
  192. wf:wire(RevealJS);
  193. _ ->
  194. wf:info(?MODULE,"error discarded ~p", Discarded)
  195. end;
  196. event(i_saw_okey) ->
  197. wf:info(?MODULE,"i_saw_okey!"),
  198. GameId = get(okey_game_id),
  199. wf:wire(protocol:i_saw_okey(wf:to_list(GameId)));
  200. event(i_have_8_tashes) ->
  201. wf:info(?MODULE,"i_gave_8_tashes!"),
  202. GameId = get(okey_game_id),
  203. wf:wire(protocol:i_have_8_tashes(wf:to_list(GameId)));
  204. event(pause) ->
  205. Action =
  206. case get(game_okey_pause) of
  207. X when X == resume orelse X == undefined ->
  208. put(game_okey_pause, pause),
  209. okey:update(pause, [#button{id = pause, body = "Resume", postback = pause}]),
  210. "pause";
  211. pause ->
  212. put(game_okey_pause, resume),
  213. okey:update(pause, [#button{id = pause, body = <<"Pause">>, postback = pause}]),
  214. "resume"
  215. end,
  216. GameId = get(okey_game_id),
  217. wf:wire(protocol:pause(wf:to_list(GameId), wf:f("~p", [Action])));
  218. %event({binary,M}) -> {ok,<<"Hello">>};
  219. event({client,{message,From,Name,To,Message}}) ->
  220. wf:info(?MODULE,"Online Chat Message from ~p(~p) to ~p:~n ~p~n",[From,Name,To,Message]),
  221. wf:send(To,{server,{chat_message,{From,Name},To,wf:to_binary(Message)}}),
  222. ok;
  223. %event({client,{chat,GameId,Name,Message}}) ->
  224. % wf:info(?MODULE,"In-Game Chat Message from ~p(~p):~n ~p~n",[GameId,Name,Message]),
  225. % ok;
  226. event({client,Message}) ->
  227. wf:info(?MODULE,"Client: ~p", [Message]),
  228. case wf:session(<<"game_pid">>) of
  229. undefined -> skip;
  230. GamePid -> SyncRes = game_session:process_request(GamePid, Message),
  231. wf:info(?MODULE,"Sync Result: ~p",[SyncRes]) end;
  232. event({server, {game_event, _, okey_game_started, Args}}) ->
  233. wf:info(?MODULE,"Game Started: ~p", [Args]),
  234. {_, Tiles} = lists:keyfind(tiles, 1, Args),
  235. TilesList = [tash(C, V) || {_, C, V} <- Tiles],
  236. wf:info(?MODULE,"Tile List: ~p",[TilesList]),
  237. case lists:keyfind(gosterge, 1, Args) of
  238. {_, {_, C, V}} ->
  239. wf:info(?MODULE,"Gosterge: ~p ~p",[C,V]),
  240. okey:update(gosterge, #label{id = gosterge, body = wf:to_binary(["Gosterge: ", wf:to_list(C), " ", wf:to_list(V)])});
  241. _ -> ok end,
  242. put(game_okey_tiles, TilesList),
  243. put(game_okey_pause, resume),
  244. redraw_istaka(TilesList);
  245. event({server, {game_event, _, okey_game_player_state, Args}}) ->
  246. wf:info(?MODULE,"Player State: ~p", [Args]),
  247. case lists:keyfind(whos_move, 1, Args) of
  248. {_, null} -> ok;
  249. {_, WhosMove} ->
  250. Players = get(okey_players),
  251. #player{label = X} = lists:keyfind(WhosMove, #player.id, Players),
  252. case X of
  253. null -> skip;
  254. false -> skip;
  255. X -> select(X), put(okey_turn_mark,X) end,
  256. case lists:keyfind(gosterge, 1, Args) of
  257. {_, {_, C, V}} ->
  258. okey:update(gosterge, #label{id = gosterge, body = wf:to_binary(["Gosterge: ", wf:to_list(C), " ", wf:to_list(V)])});
  259. _ -> ok end,
  260. {_, Tiles} = lists:keyfind(tiles, 1, Args),
  261. TilesList = [tash(C, V)|| {_, C, V} <- Tiles],
  262. wf:info(?MODULE,"Istaka on State"),
  263. redraw_istaka(TilesList),
  264. put(game_okey_tiles, TilesList),
  265. {_, Piles} = lists:keyfind(piles, 1, Args),
  266. UpdatedPlayers = [ begin
  267. Player = #player{discard = RightPileComboId}
  268. = lists:keyfind(PlayerId, #player.id, Players),
  269. ConvertedPile = [ tash(C, V) || {_, C, V} <- Pile],
  270. redraw_tiles(ConvertedPile, #dropdown{id = RightPileComboId}),
  271. Player#player{history = ConvertedPile}
  272. end || {PlayerId, Pile} <- Piles ],
  273. put(okey_players, lists:sort(fun(#player{label = E1}, #player{label = E2}) ->
  274. E1 < E2 end, UpdatedPlayers));
  275. _ -> ok end;
  276. event({server, {game_event, _, okey_tile_taken, Args}}) ->
  277. wf:info(?MODULE,"Taken: ~p", [Args]),
  278. Im = get(okey_im),
  279. {_, PlayerId} = lists:keyfind(player, 1, Args),
  280. case lists:keyfind(revealed, 1, Args) of
  281. {_, {_, C, V}} ->
  282. if Im == PlayerId ->
  283. TilesList = [ tash(C, V) | get(game_okey_tiles)],
  284. %%wf:info(?MODULE,"Tiles: ~p",[TilesList]),
  285. put(game_okey_tiles, TilesList),
  286. redraw_istaka(TilesList);
  287. true -> ok end,
  288. case lists:keyfind(pile, 1, Args) of
  289. {_, 1} -> %% have taken from left
  290. Players = get(okey_players),
  291. #player{take=From} = lists:keyfind(PlayerId,#player.id,Players),
  292. LeftPlayer = #player{discard=Combo,history=DiscardHistory}
  293. = lists:keyfind(From,#player.label,Players),
  294. History = lists:keydelete({C, V}, 2, DiscardHistory),
  295. redraw_tiles(History, #dropdown{id=Combo}),
  296. put(okey_players,update_players(LeftPlayer#player{history=History},Players));
  297. _ -> ok end;
  298. _ -> ok end;
  299. event({server, {game_event, _, okey_tile_discarded, Args}}) ->
  300. wf:info(?MODULE,"Discarded: ~p", [Args]),
  301. Im = get(okey_im),
  302. {_, PlayerId} = lists:keyfind(player, 1, Args),
  303. {_, {_, C, V}} = lists:keyfind(tile, 1, Args),
  304. if Im == PlayerId ->
  305. TilesListOld = get(game_okey_tiles),
  306. TilesList = lists:keydelete({C, V}, 2, TilesListOld),
  307. put(game_okey_tiles, TilesList),
  308. redraw_istaka(TilesList);
  309. true -> ok end,
  310. Players = get(okey_players),
  311. Player = #player{discard = RightPileComboId, history = OldRightPile}
  312. = lists:keyfind(PlayerId, #player.id, Players),
  313. NewRightPile = [ tash(C, V) | OldRightPile],
  314. redraw_tiles(NewRightPile, #dropdown{id = RightPileComboId}),
  315. UpdatedPlayer = Player#player{history = NewRightPile},
  316. UpdatedPlayers = update_players(UpdatedPlayer, Players),
  317. put(okey_players, UpdatedPlayers);
  318. event({server,{game_event, _Game, okey_turn_timeout, Args}}) ->
  319. wf:info(?MODULE,"Turn Timeout: ~p", [Args]);
  320. %%event({server, {game_paused, _, _Gameid, Action, Who, _}}) ->
  321. %% Im = get(okey_im),
  322. %%
  323. %% if Im =/= Who ->
  324. %% put(game_okey_pause, Action),
  325. %% okey:update(pause, [#button{id = pause, body = case Action of pause -> "Resume"; resume -> "Pause" end, postback = pause}]);
  326. %% true -> ok end;
  327. event({server, {game_event, _, okey_game_info, Args}}) ->
  328. wf:info(?MODULE,"Game Info: ~p", [Args]),
  329. {_, PlayersInfo} = lists:keyfind(players, 1, Args),
  330. [okey:update(ElementId, [Element]) || {ElementId, Element} <- ?RESET_ELEMENTS],
  331. PlayersTempl = [
  332. #player{label = player1, discard = h1, take = player4},
  333. #player{label = player2, discard = h2, take = player1},
  334. #player{label = player3, discard = h3, take = player2},
  335. #player{label = player4, discard = h4, take = player3}],
  336. Players = lists:zipwith(fun(Players, #'PlayerInfo'{id = Id} = PI) ->
  337. Players#player{id=Id,info=PI} end, PlayersTempl, PlayersInfo),
  338. put(okey_players, Players),
  339. redraw_players(Players);
  340. event({server,{game_event, _, player_left, Args}}) ->
  341. wf:info(?MODULE,"Player Left: ~p", [Args]),
  342. {_, OldPlayerId} = lists:keyfind(player, 1, Args),
  343. {_, PI} = lists:keyfind(replacement, 1, Args),
  344. #'PlayerInfo'{id = NewPlayerId} = PI,
  345. OldPlayers = get(okey_players),
  346. OldPlayer = lists:keyfind(OldPlayerId, #player.id, OldPlayers),
  347. NewPlayers = update_players(OldPlayer#player{id=NewPlayerId,info=PI}, OldPlayers),
  348. put(okey_players, NewPlayers),
  349. redraw_players(NewPlayers),
  350. case get(okey_turn_mark) of undefined -> ok; X -> select(X) end;
  351. event({server,{game_event, _, okey_next_turn, Args}}) ->
  352. wf:info(?MODULE,"Next Turn: ~p", [Args]),
  353. {player, PlayerId} = lists:keyfind(player, 1, Args),
  354. #player{label = LabelId} = lists:keyfind(PlayerId, #player.id, get(okey_players)),
  355. case get(okey_turn_mark) of
  356. undefined -> ok;
  357. OldLabelId -> unselect(OldLabelId) end,
  358. select(LabelId),
  359. put(okey_turn_mark, LabelId);
  360. event({server,terminate}) -> event(terminate);
  361. event({register,User}) -> wf:info(?MODULE,"Register: ~p",[User]), kvs:add(User), wf:user(User);
  362. event({login,User}) -> wf:info(?MODULE,"Login: ~p",[User]), kvs:put(User), wf:user(User), event(init);
  363. event({counter,Res}) -> Pid = self(), spawn(fun() -> Pid ! {server,{online_number,length(game:online())}} end);
  364. event({user_online,User}) -> wf:info(?MODULE,"User ~p goes Online",[User#user.id]), self() ! {server,{online,User#user.id,User#user.names,User#user.surnames}};
  365. event({user_offline,User}) -> self() ! {server,{offline,User#user.id,User#user.names,User#user.surnames}};
  366. event(_Event) -> wf:info(?MODULE,"Unknown Event: ~p", [_Event]).
  367. %api_event(X,Y,Z) -> avz:api_event(X,Y,Z).