From 71c2f729208cecb039e2bd753a50b55c2788f2d0 Mon Sep 17 00:00:00 2001 From: Nathanael Sensfelder Date: Wed, 2 Jan 2019 01:46:34 +0100 Subject: Bounties? Somehow, Dialyzer does not see the type issues with src/bounty/bnt_join_battle.erl, but there are btl_character and rst_character mix-ups. --- conf/yaws.conf.m4 | 2 +- other/db_bounty.txt | 18 ++ src/battle/query/btl_join.erl | 183 ++++++++++++ src/battle/query/btl_join.erl.next | 168 ----------- src/battle/reply/btl_add_portrait.erl | 29 ++ src/battle/struct/btl_pending_battle.erl | 3 + src/bounty/bnt_generate_player.erl | 191 ++++++++++++ src/bounty/bnt_grant_land.erl | 58 ++++ src/bounty/bnt_join_battle.erl | 483 +++++++++++++++++++++++++++++++ src/login/query/lgn_sign_up.erl | 2 +- src/map/struct/map_map.erl | 2 +- src/query/qry_shim.erl | 8 +- src/special/spe_battle.erl | 438 ---------------------------- src/special/spe_map.erl | 58 ---- src/special/spe_player.erl | 191 ------------ 15 files changed, 972 insertions(+), 862 deletions(-) create mode 100644 other/db_bounty.txt create mode 100644 src/battle/query/btl_join.erl delete mode 100644 src/battle/query/btl_join.erl.next create mode 100644 src/battle/reply/btl_add_portrait.erl create mode 100644 src/bounty/bnt_generate_player.erl create mode 100644 src/bounty/bnt_grant_land.erl create mode 100644 src/bounty/bnt_join_battle.erl delete mode 100644 src/special/spe_battle.erl delete mode 100644 src/special/spe_map.erl delete mode 100644 src/special/spe_player.erl diff --git a/conf/yaws.conf.m4 b/conf/yaws.conf.m4 index 00dfe16..0773310 100644 --- a/conf/yaws.conf.m4 +++ b/conf/yaws.conf.m4 @@ -110,7 +110,7 @@ keepalive_timeout = 30000 listen = 0.0.0.0 docroot = __MAKEFILE_WWW_DIR auth_log = true - appmods = btl_character_turn btl_load map_load map_update lgn_sign_in lgn_sign_up lgn_recovery lgn_get_player_id rst_load rst_update plr_load plr_get_battles + appmods = btl_character_turn btl_load btl_join map_load map_update lgn_sign_in lgn_sign_up lgn_recovery lgn_get_player_id rst_load rst_update plr_load plr_get_battles start_mod = qry_handler partial_post_size = 1000000 diff --git a/other/db_bounty.txt b/other/db_bounty.txt new file mode 100644 index 0000000..d31226a --- /dev/null +++ b/other/db_bounty.txt @@ -0,0 +1,18 @@ +Designing with a "it can crash at any point" mentality ++ can't combine DB queries in an atomic manner += Potential for partially completed tasks, "corrupting" the global DB. + +A solution could be having "bounty" entries, which work as follows: +A process P0 needs to do tasks T0, then T1, then T2. +P0 creates a bounty B0: +{ + not_before: 60s. + task: T0_T1_T2. + params: [{T0.id, T1.id, 20] +} +P0 adds B0 to the Bounty DB. +P0 attempts T0, T1, and T2. +P0 removes B0 from the Bounty DB. + +There are other processes trying to access available bounties (i.e. bounties +for which the "not_before" has expired) to complete them. diff --git a/src/battle/query/btl_join.erl b/src/battle/query/btl_join.erl new file mode 100644 index 0000000..a723a8b --- /dev/null +++ b/src/battle/query/btl_join.erl @@ -0,0 +1,183 @@ +-module(btl_join). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-include("../../../include/yaws_api.hrl"). + +-type mode() :: (attack | defend | {invalid, binary()}). + +-record +( + input, + { + player_id :: shr_player:id(), + session_token :: binary(), + mode :: mode(), + size :: non_neg_integer(), + roster_ixs :: list(non_neg_integer()), + map_id :: ataxia_id:type() + } +). + + +-type input() :: #input{}. +-type defend_query_state() :: 'ok'. +-type attack_query_state() :: 'ok'. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export([out/1]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec parse_input (binary()) -> input(). +parse_input (Req) -> + JSONReqMap = jiffy:decode(Req, [return_maps]), + PlayerID = maps:get(<<"pid">>, JSONReqMap), + SessionToken = maps:get(<<"stk">>, JSONReqMap), + + Mode = + case maps:get(<<"m">>, JSONReqMap) of + <<"a">> -> attack; + <<"d">> -> defend; + V -> {invalid, V} + end, + + true = ((Mode == attack) or (Mode == defend)), + + Size = + case maps:get(<<"s">>, JSONReqMap) of + <<"s">> -> 8; + <<"m">> -> 16; + <<"l">> -> 24; + _ -> 0 + end, + + Roster = maps:get(<<"r">>, JSONReqMap), + MapID = maps:get(<<"map_id">>, JSONReqMap), + + #input + { + player_id = PlayerID, + session_token = SessionToken, + mode = Mode, + size = Size, + roster_ixs = Roster, + map_id = MapID + }. + +-spec authenticate_user (input()) -> ('ok' | 'error'). +authenticate_user (Input) -> + PlayerID = Input#input.player_id, + SessionToken = Input#input.session_token, + + Player = shr_timed_cache:fetch(player_db, any, PlayerID), + + case shr_security:credentials_match(SessionToken, Player) of + true -> ok; + _ -> error + end. + +-spec handle_attack (input()) -> 'ok'. +handle_attack (Input) -> + PlayerID = Input#input.player_id, + SelectedCharacterIXs = Input#input.roster_ixs, + PlayerDBUser = ataxia_security:user_from_id(PlayerID), + PartySize = length(SelectedCharacterIXs), + + % TODO: be less brutal if none is found. + {ok, AvailablePendingBattle, _ID} = + ataxia_client:update_and_fetch_any + ( + btl_pending, + PlayerDBUser, + ataxic:update_lock + ( + ataxic:apply_function + ( + ataxia_lock, + locked, + [ + ataxic:constant(PlayerDBUser), + ataxic:constant(60) + ] + ) + ), + ataxic:ge + ( + ataxic:field + ( + ataxia_entry:get_value_field(), + ataxic:field + ( + btl_pending_battle:get_free_slots_field(), + ataxic:current_value() + ) + ), + ataxic:constant(PartySize) + ) + ), + + bnt_join_battle:attempt + ( + PlayerID, + SelectedCharacterIXs, + AvailablePendingBattle + ), + + ok. +-spec handle_defend (input()) -> 'ok'. +handle_defend (Input) -> + PlayerID = Input#input.player_id, + SelectedCharacterIXs = Input#input.roster_ixs, + MapID = Input#input.map_id, + + bnt_join_battle:generate(PlayerID, MapID, SelectedCharacterIXs), + + ok. + +-spec fetch_attack_data (input()) -> attack_query_state(). +fetch_attack_data (_Input) -> ok. % TODO + +-spec fetch_defend_data (input()) -> defend_query_state(). +fetch_defend_data (_Input) -> ok. % TODO + +-spec authorize_attack (attack_query_state(), input()) -> 'ok'. +authorize_attack (_QueryState, _Input) -> ok. % TODO + +-spec authorize_defend (defend_query_state(), input()) -> 'ok'. +authorize_defend (_QueryState, _Input) -> ok. % TODO + +-spec handle (binary()) -> binary(). +handle (Req) -> + Input = parse_input(Req), + case authenticate_user(Input) of + ok -> + case Input#input.mode of + attack -> + QueryState = fetch_attack_data(Input), + ok = authorize_attack(QueryState, Input), + handle_attack(Input); + + defend -> + QueryState = fetch_defend_data(Input), + ok = authorize_defend(QueryState, Input), + handle_defend(Input) + end, + jiffy:encode([shr_okay:generate()]); + + error -> jiffy:encode([shr_disconnected:generate()]) + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +out(A) -> + { + content, + "application/json; charset=UTF-8", + handle(A#arg.clidata) + }. diff --git a/src/battle/query/btl_join.erl.next b/src/battle/query/btl_join.erl.next deleted file mode 100644 index 3ab7be8..0000000 --- a/src/battle/query/btl_join.erl.next +++ /dev/null @@ -1,168 +0,0 @@ --module(btl_join). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --include("../../../include/yaws_api.hrl"). - --type mode() :: (attack | defend | {invalid, binary()}). - --record -( - input, - { - player_id :: shr_player:id(), - session_token :: binary(), - mode :: mode(), - size :: non_neg_integer(), - roster_ixs :: list(non_neg_integer()), - map_id :: string() - } -). - --record -( - query_state, - { - battle :: btl_battle:type() - } -). - --type input() :: #input{}. --type query_state() :: #query_state{}. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --export([out/1]). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec parse_input (binary()) -> input(). -parse_input (Req) -> - JSONReqMap = jiffy:decode(Req, [return_maps]), - PlayerID = maps:get(<<"pid">>, JSONReqMap), - SessionToken = maps:get(<<"stk">>, JSONReqMap), - - Mode = - case maps:get(<<"m">>, JSONReqMap) of - <<"a">> -> attack; - <<"b">> -> defend; - V -> {invalid, V} - end, - - true = ((Mode == attack) or (Mode == defend)), - - Size = - case maps:get(<<"s">>, JSONReqMap) of - <<"s">> -> 8; - <<"m">> -> 16; - <<"l">> -> 24; - _ -> 0 - end, - - Roster = maps:get(<<"r">>, JSONReqMap), - MapID = maps:get(<<"map_id">>, JSONReqMap), - - #input - { - player_id = PlayerID, - session_token = SessionToken, - mode = Mode, - size = Size, - roster_ixs = Roster, - map_id = MapID - }. - --spec authenticate_user (input()) -> ('ok' | 'error'). -authenticate_user (Input) -> - PlayerID = Input#input.player_id, - SessionToken = Input#input.session_token, - - Player = shr_timed_cache:fetch(player_db, any, PlayerID), - - case shr_security:credentials_match(SessionToken, Player) of - true -> ok; - _ -> error - end. - --spec handle_new_attack (input()) -> query_state(). -handle_new_attack (Input) -> - PlayerID = <<"">>, - PlayerDBUser = ataxia_security:user_from_id(PlayerID), - PartySize = 8, - - AvailableBattle = - ataxia_client:update_and_fetch_any - ( - btl_pending, - PlayerDBUser, - ataxic:update_lock - ( - ataxic:apply_function - ( - ataxia_lock, - locked, - [ - ataxic:constant(PlayerDBUser), - ataxic:constant(60) - ] - ) - ), - ataxic:ge - ( - ataxic:field - ( - ataxia_entry:get_value_field(), - ataxic:field - ( - btl_pending_battle:get_free_slots_field(), - ataxic:current_value() - ) - ), - ataxic:constant(PartySize) - ) - ), - - ... - - --spec fetch_data (input()) -> query_state(). -fetch_data (Input) -> - PlayerID = Input#input.player_id, - BattleID = Input#input.battle_id, - - Battle = shr_timed_cache:fetch(battle_db, PlayerID, BattleID), - - #query_state - { - battle = Battle - }. - - --spec generate_reply(query_state(), input()) -> binary(). -generate_reply (QueryState, Input) -> - - Output. - --spec handle (binary()) -> binary(). -handle (Req) -> - Input = parse_input(Req), - case authenticate_user(Input) of - ok -> - QueryState = fetch_data(Input), - generate_reply(QueryState, Input); - - error -> jiffy:encode([shr_disconnected:generate()]) - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -out(A) -> - { - content, - "application/json; charset=UTF-8", - handle(A#arg.clidata) - }. diff --git a/src/battle/reply/btl_add_portrait.erl b/src/battle/reply/btl_add_portrait.erl new file mode 100644 index 0000000..a634a04 --- /dev/null +++ b/src/battle/reply/btl_add_portrait.erl @@ -0,0 +1,29 @@ +-module(btl_add_portrait). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export([generate/1]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec generate (shr_portrait:type()) -> {list(any())}. +generate (Portrait) -> + { + [ + {<<"msg">>, <<"add_portrait">>}, + {<<"id">>, shr_portrait:get_id(Portrait)}, + {<<"nam">>, shr_portrait:get_name(Portrait)}, + {<<"bid">>, shr_portrait:get_body_id(Portrait)}, + {<<"iid">>, shr_portrait:get_icon_id(Portrait)} + ] + }. diff --git a/src/battle/struct/btl_pending_battle.erl b/src/battle/struct/btl_pending_battle.erl index 6e21f79..cecaeb5 100644 --- a/src/battle/struct/btl_pending_battle.erl +++ b/src/battle/struct/btl_pending_battle.erl @@ -18,6 +18,9 @@ -opaque type() :: #pending_battle{}. -export_type([type/0, id/0]). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/bounty/bnt_generate_player.erl b/src/bounty/bnt_generate_player.erl new file mode 100644 index 0000000..e02a94b --- /dev/null +++ b/src/bounty/bnt_generate_player.erl @@ -0,0 +1,191 @@ +-module(bnt_generate_player). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export([attempt/3]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec reserve_login (binary(), binary()) -> 'ok'. +reserve_login (UsernameLC, EmailLC) -> + ok = ataxia_client:reserve(login_db, UsernameLC), + ok = ataxia_client:reserve(login_db, EmailLC), + + ok. + +-spec finalize_login (binary(), binary(), binary()) -> 'ok'. +finalize_login (UsernameLC, EmailLC, PlayerID) -> + LoginUpdateQueryOps = + ataxic:sequence_meta + ( + [ + ataxic:update_value(ataxic:constant(PlayerID)), + ataxic:update_read_permission + ( + ataxic:constant + ( + ataxia_security:allow_only + ( + ataxia_security:any() + ) + ) + ), + ataxic:update_write_permission + ( + ataxic:constant + ( + ataxia_security:allow_only + ( + ataxia_security:user_from_id(PlayerID) + ) + ) + ) + ] + ), + + ok = + ataxia_client:update + ( + login_db, + ataxia_security:janitor(), + LoginUpdateQueryOps, + UsernameLC + ), + + ok = + ataxia_client:update + ( + login_db, + ataxia_security:janitor(), + LoginUpdateQueryOps, + EmailLC + ), + + 'ok'. + +-spec generate_inventory (ataxia_id:type()) -> ataxia_id:type(). +generate_inventory (PlayerID) -> + Inventory = shr_inventory:new(PlayerID), + + {ok, InventoryID} = + ataxia_client:add + ( + inventory_db, + ataxia_security:allow_only(ataxia_security:any()), + ataxia_security:allow_only(ataxia_security:user_from_id(PlayerID)), + Inventory + ), + + InventoryID. + +-spec generate_roster (ataxia_id:type()) -> ataxia_id:type(). +generate_roster (PlayerID) -> + Roster = rst_roster:new(PlayerID), + {ok, RosterID} = + ataxia_client:add + ( + roster_db, + ataxia_security:allow_only(ataxia_security:any()), + ataxia_security:allow_only(ataxia_security:user_from_id(PlayerID)), + Roster + ), + + RosterID. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec attempt (binary(), binary(), binary()) -> shr_player:type(). +attempt (Username, Password, Email) -> + UsernameLC = string:lowercase(Username), + EmailLC = string:lowercase(Email), + + ok = reserve_login(UsernameLC, EmailLC), + + Player = shr_player:new(<<"">>, Username, Password, Email), + + JanitorOnlyPermission = + ataxia_security:allow_only(ataxia_security:janitor()), + + {ok, PlayerID} = + ataxia_client:add + ( + player_db, + JanitorOnlyPermission, + JanitorOnlyPermission, + Player + ), + + shr_janitor:new(player_db, PlayerID), + + InvID = generate_inventory(PlayerID), + RosterID = generate_roster(PlayerID), + + PlayerUpdateQueryOps = + ataxic:sequence_meta + ( + [ + ataxic:update_value + ( + ataxic:sequence + ( + [ + ataxic:update_field + ( + shr_player:get_id_field(), + ataxic:constant(PlayerID) + ), + ataxic:update_field + ( + shr_player:get_inventory_id_field(), + ataxic:constant(InvID) + ), + ataxic:update_field + ( + shr_player:get_roster_id_field(), + ataxic:constant(RosterID) + ) + ] + ) + ), + ataxic:update_read_permission + ( + ataxic:constant + ( + ataxia_security:allow_only(ataxia_security:any()) + ) + ), + ataxic:update_write_permission + ( + ataxic:constant + ( + ataxia_security:allow_only + ( + ataxia_security:user_from_id(PlayerID) + ) + ) + ) + ] + ), + + ok = finalize_login(UsernameLC, EmailLC, PlayerID), + + ok = + ataxia_client:update + ( + player_db, + ataxia_security:janitor(), + PlayerUpdateQueryOps, + PlayerID + ), + + + Result = shr_player:set_id(PlayerID, Player), + + Result. diff --git a/src/bounty/bnt_grant_land.erl b/src/bounty/bnt_grant_land.erl new file mode 100644 index 0000000..1a8a62e --- /dev/null +++ b/src/bounty/bnt_grant_land.erl @@ -0,0 +1,58 @@ +-module(bnt_grant_land). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export([attempt/1]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec attempt (ataxia_id:type()) -> map_map:type(). +attempt (OwnerID) -> + Map = map_map:default(OwnerID), + + {ok, MapID} = + ataxia_client:add + ( + map_db, + ataxia_security:allow_only(ataxia_security:any()), + ataxia_security:allow_only(ataxia_security:user_from_id(OwnerID)), + Map + ), + + MapSummary = shr_map_summary:new(MapID, <<"Untitled Map">>), + + PlayerUpdateQueryOp = + ataxic:update_value + ( + ataxic:update_field + ( + shr_player:get_map_summaries_field(), + ataxic:apply_function + ( + lists, + append, + [ataxic:constant([MapSummary]), ataxic:current_value()] + ) + ) + ), + + ok = + ataxia_client:update + ( + player_db, + ataxia_security:admin(), + PlayerUpdateQueryOp, + OwnerID + ), + + Map. diff --git a/src/bounty/bnt_join_battle.erl b/src/bounty/bnt_join_battle.erl new file mode 100644 index 0000000..1028166 --- /dev/null +++ b/src/bounty/bnt_join_battle.erl @@ -0,0 +1,483 @@ +-module(bnt_join_battle). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export([generate/3, attempt/3]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%% USED IDS COLLECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec update_ordset + ( + ordsets:ordset(any()), + ordsets:ordset(any()) + ) + -> ataxic:basic(). +update_ordset (New, Old) -> + AddedElements = ordsets:subtract(New, Old), + + ataxic:sequence + ( + lists:map + ( + fun (V) -> + ataxic:apply_function + ( + ordsets, + add_element, + [ + ataxic:constant(V), + ataxic:current_value() + ] + ) + end, + ordsets:to_list(AddedElements) + ) + ). + +-spec get_equipment_ids + ( + orddict:orddict(non_neg_integer(), btl_character:type()) + ) + -> + { + ordsets:ordset(shr_portrait:id()), + ordsets:ordset(shr_weapon:id()), + ordsets:ordset(shr_armor:id()) + }. +get_equipment_ids (Characters) -> + { + UsedPortraitIDs, + UsedWeaponIDs, + UsedArmorIDs + } = + orddict:fold + ( + fun (_IX, Character, {UPIDs, UWIDs, UAIDs}) -> + {MWpID, SWpID} = btl_character:get_weapon_ids(Character), + AID = btl_character:get_armor_id(Character), + PID = btl_character:get_portrait_id(Character), + { + ordsets:add_element(PID, UPIDs), + ordsets:add_element(MWpID, ordsets:add_element(SWpID, UWIDs)), + ordsets:add_element(AID, UAIDs) + } + end, + {ordsets:new(), ordsets:new(), ordsets:new()}, + Characters + ), + + {UsedPortraitIDs, UsedWeaponIDs, UsedArmorIDs}. + + +%%%% ROSTERS HANDLING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec get_forbidden_locations + ( + btl_battle:type() + ) + -> ordsets:ordset(btl_location:type()). +get_forbidden_locations (Battle) -> + orddict:fold + ( + fun (_IX, Char, Set) -> + ordsets:add_element(btl_character:get_location(Char), Set) + end, + ordsets:new(), + btl_battle:get_characters(Battle) + ). + +-spec find_random_location + ( + btl_map:type(), + ordsets:ordset(btl_location:type()) + ) + -> {btl_location:type(), shr_tile:type()}. +find_random_location (Map, ForbiddenLocations) -> + MapWidth = btl_map:get_width(Map), + MapHeight = btl_map:get_height(Map), + + Candidate = + { + shr_roll:between(0, (MapWidth - 1)), + shr_roll:between(0, (MapHeight - 1)) + }, + + IsForbidden = ordsets:is_element(Candidate, ForbiddenLocations), + + case IsForbidden of + true -> find_random_location(Map, ForbiddenLocations); + + _ -> + Tile = + shr_tile:from_class_id + ( + shr_tile:extract_main_class_id + ( + btl_map:get_tile_instance(Candidate, Map) + ) + ), + + case (shr_tile:get_cost(Tile) > 200) of + true -> find_random_location(Map, ForbiddenLocations); + + false -> {Candidate, Tile} + end + end. + +-spec get_glyphs_omnimods (rst_character:type()) -> shr_omnimods:type(). +get_glyphs_omnimods (RosterChar) -> + GlyphBoardID = rst_character:get_glyph_board_id(RosterChar), + GlyphIDs = rst_character:get_glyph_ids(RosterChar), + GlyphBoard = shr_glyph_board:from_id(GlyphBoardID), + Glyphs = lists:map(fun shr_glyph:from_id/1, GlyphIDs), + case shr_glyph_board:get_omnimods_with_glyphs(Glyphs, GlyphBoard) of + {ok, Result} -> Result; + error -> shr_omnimods:new([], [], [], []) + end. + +-spec create_character + ( + non_neg_integer(), + rst_character:type(), + btl_map:type(), + ordsets:ordset(btl_location:type()) + ) + -> btl_character:type(). +create_character (PlayerIX, RosterChar, Map, ForbiddenLocations) -> + {Location, Tile} = find_random_location(Map, ForbiddenLocations), + TileOmnimods = shr_tile:get_omnimods(Tile), + GlyphsOmnimods = get_glyphs_omnimods(RosterChar), + + Result = + btl_character:new + ( + PlayerIX, + rst_character:get_name(RosterChar), + optional, % TODO: link this to roster. + GlyphsOmnimods, + rst_character:get_portrait_id(RosterChar), + rst_character:get_weapon_ids(RosterChar), + rst_character:get_armor_id(RosterChar), + Location, + TileOmnimods + ), + + Result. + +-spec handle_characters + ( + list(rst_character:type()), + non_neg_integer(), + btl_map:type(), + ordsets:ordset(btl_location:type()), + non_neg_integer(), + orddict:orddict(non_neg_integer(), btl_character:type()), + list(ataxic:basic()) + ) + -> + { + orddict:orddict(non_neg_integer(), btl_character:type()), + list(ataxic:basic()) + }. +handle_characters +( + [], + _PlayerIX, + _Map, + _UsedLocations, + _NextCharIX, + Characters, + AtaxicUpdates +) -> + {Characters, AtaxicUpdates}; +handle_characters +( + [RosterCharacter|NextRosterCharacters], + PlayerIX, + Map, + UsedLocations, + NextCharIX, + Characters, + AtaxicUpdates +) -> + NewCharacter = + create_character(PlayerIX, RosterCharacter, Map, UsedLocations), + + NewCharacters = orddict:store(NextCharIX, NewCharacter, Characters), + + NewUpdate = + ataxic:apply_function + ( + orddict, + store, + [ + ataxic:constant(NextCharIX), + ataxic:constant(NewCharacter), + ataxic:current_value() + ] + ), + + handle_characters + ( + NextRosterCharacters, + PlayerIX, + Map, + [btl_character:get_location(NewCharacter)|UsedLocations], + (NextCharIX + 1), + NewCharacters, + [NewUpdate|AtaxicUpdates] + ). + +-spec add_player + ( + shr_player:id(), + btl_battle:type() + ) + -> {btl_battle:type(), non_neg_integer(), ataxic:basic()}. +add_player (PlayerID, Battle) -> + Players = btl_battle:get_players(Battle), + + PlayerIX = orddict:size(Players), + NewPlayer = btl_player:new(PlayerIX, 0, PlayerID), + + NewPlayers = orddict:store(PlayerIX, NewPlayer, Players), + S0Battle = btl_battle:set_players(NewPlayers, Battle), + + Update = + ataxic:update_field + ( + btl_battle:get_players_field(), + ataxic:apply_function + ( + orddict, + store, + [ + ataxic:constant(PlayerIX), + ataxic:constant(NewPlayer), + ataxic:current_value() + ] + ) + ), + + {S0Battle, PlayerIX, Update}. + +-spec add_characters + ( + list(rst_character:type()), + non_neg_integer(), + btl_battle:type() + ) + -> {btl_battle:type(), ataxic:basic()}. +add_characters (RosterCharacters, PlayerIX, Battle) -> + CurrentCharacters = btl_battle:get_characters(Battle), + NextCharacterIX = orddict:size(CurrentCharacters), + Map = btl_battle:get_map(Battle), + + ForbiddenLocations = get_forbidden_locations(Battle), + + {NewCharacters, CharactersUpdates} = + handle_characters + ( + RosterCharacters, + PlayerIX, + Map, + ForbiddenLocations, + NextCharacterIX, + CurrentCharacters, + [] + ), + + {UsedPortraitIDs, UsedWeaponIDs, UsedArmorIDs} = + get_equipment_ids(RosterCharacters), + + OldPortraitIDs = btl_battle:get_used_portrait_ids(Battle), + PortraitIDsUpdate = + ataxic:update_field + ( + btl_battle:get_used_portrait_ids_field(), + update_ordset(UsedPortraitIDs, OldPortraitIDs) + ), + + OldWeaponIDs = btl_battle:get_used_portrait_ids(Battle), + WeaponIDsUpdate = + ataxic:update_field + ( + btl_battle:get_used_weapon_ids_field(), + update_ordset(UsedWeaponIDs, OldWeaponIDs) + ), + + OldArmorIDs = btl_battle:get_used_armor_ids(Battle), + ArmorIDsUpdate = + ataxic:update_field + ( + btl_battle:get_used_armor_ids_field(), + update_ordset(UsedArmorIDs, OldArmorIDs) + ), + + S0Battle = btl_battle:set_characters(NewCharacters, Battle), + S1Battle = + btl_battle:set_used_armor_ids + ( + ordsets:union(UsedArmorIDs, OldArmorIDs), + btl_battle:set_used_weapon_ids + ( + ordsets:union(UsedWeaponIDs, OldWeaponIDs), + btl_battle:set_used_portrait_ids + ( + ordsets:union(UsedPortraitIDs, OldPortraitIDs), + S0Battle + ) + ) + ), + + Update = + ataxic:sequence + ( + [ + ataxic:update_field + ( + btl_battle:get_characters_field(), + ataxic:sequence(CharactersUpdates) + ), + PortraitIDsUpdate, + WeaponIDsUpdate, + ArmorIDsUpdate + ] + ), + + {S1Battle, Update}. + +-spec get_roster_characters + ( + shr_player:id(), + list(non_neg_integer()) + ) + -> list(rst_character:type()). +get_roster_characters (PlayerID, SelectedRosterCharacterIXs) -> + Player = shr_timed_cache:fetch(player_db, ataxia_security:any(), PlayerID), + RosterID = shr_player:get_roster_id(Player), + Roster = + shr_timed_cache:fetch + ( + roster_db, + ataxia_security:user_from_id(PlayerID), + RosterID + ), + + RosterCharacters = rst_roster:get_characters(Roster), + + lists:map + ( + fun (CharIX) -> + orddict:fetch(CharIX, RosterCharacters) + end, + SelectedRosterCharacterIXs + ). + +%%%% BATTLE CREATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec generate_battle (shr_player:id(), map_map:id()) -> btl_battle:type(). +generate_battle (PlayerID, MapID) -> + Map = + shr_timed_cache:fetch + ( + map_db, + ataxia_security:user_from_id(PlayerID), + MapID + ), + TileInstances = map_map:get_tile_instances(Map), + BattleMap = + btl_map:from_instances_tuple + ( + map_map:get_width(Map), + map_map:get_height(Map), + TileInstances + ), + + Battle = btl_battle:new(BattleMap), + + Battle. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec generate + ( + shr_player:id(), + map_map:id(), + list(non_neg_integer()) + ) + -> btl_pending_battle:type(). +generate (PlayerID, MapID, SelectedRosterCharacterIXs) -> + Battle = generate_battle(PlayerID, MapID), + PendingBattle = + btl_pending_battle:new + ( + <<"">>, + % TODO: More options than 1 vs N. + (length(SelectedRosterCharacterIXs) * 2), + Battle + ), + + attempt(PlayerID, SelectedRosterCharacterIXs, PendingBattle). + +-spec attempt + ( + shr_player:id(), + list(non_neg_integer()), + btl_pending_battle:type() + ) + -> btl_pending_battle:type(). +attempt (PlayerID, SelectedRosterCharacterIXs, PendingBattle) -> + Battle = btl_pending_battle:get_battle(PendingBattle), + RemainingSlots = + ( + btl_pending_battle:get_free_slots(PendingBattle) + - length(SelectedRosterCharacterIXs) + ), + + NewCharacters = get_roster_characters(PlayerID, SelectedRosterCharacterIXs), + {S0Battle, PlayerIX, BattleUpdate0} = add_player(PlayerID, Battle), + {S1Battle, BattleUpdate1} = + add_characters(NewCharacters, PlayerIX, S0Battle), + + S0PendingBattle = btl_pending_battle:set_battle(S1Battle, PendingBattle), + S1PendingBattle = + btl_pending_battle:set_free_slots(RemainingSlots, S0PendingBattle), + + Update = + ataxic:sequence + ( + [ + ataxic:update_field + ( + btl_pending_battle:get_battle_field(), + ataxic:sequence + ( + [ + BattleUpdate0, + BattleUpdate1 + ] + ) + ), + ataxic:update_field + ( + btl_pending_battle:get_free_slots_field(), + ataxic:constant(RemainingSlots) + ) + ] + ), + + {S1PendingBattle, Update}, + + S1PendingBattle. + + % TODO: + % if RemainingSlots = 0 -> del this, new Battle. + % Link either new Battle or current Pending Battle to player account. diff --git a/src/login/query/lgn_sign_up.erl b/src/login/query/lgn_sign_up.erl index 0632ac1..0d974ff 100644 --- a/src/login/query/lgn_sign_up.erl +++ b/src/login/query/lgn_sign_up.erl @@ -54,7 +54,7 @@ register_user (Input) -> Password = Input#input.password, Email = Input#input.email, - GeneratedPlayer = spe_player:generate(Username, Password, Email), + GeneratedPlayer = bnt_generate_player:attempt(Username, Password, Email), #query_state { diff --git a/src/map/struct/map_map.erl b/src/map/struct/map_map.erl index bfa9e5a..b8d37c9 100644 --- a/src/map/struct/map_map.erl +++ b/src/map/struct/map_map.erl @@ -3,7 +3,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --type id() :: binary(). +-type id() :: ataxia_id:type(). -record ( diff --git a/src/query/qry_shim.erl b/src/query/qry_shim.erl index 473a14c..3933c73 100644 --- a/src/query/qry_shim.erl +++ b/src/query/qry_shim.erl @@ -15,14 +15,14 @@ -spec generate_player_0 () -> shr_player:type(). generate_player_0 () -> Player = - spe_player:generate + bnt_generate_player:attempt ( <<"Player1">>, <<"Kalimer0">>, <<"Player1@tacticians.online">> ), - spe_map:grant_additional(shr_player:get_id(Player)), + bnt_grant_land:attempt(shr_player:get_id(Player)), Player. @@ -30,14 +30,14 @@ generate_player_0 () -> -spec generate_player_1 () -> shr_player:type(). generate_player_1 () -> Player = - spe_player:generate + bnt_generate_player:attempt ( <<"Player2">>, <<"Kalimer1">>, <<"Player2@tacticians.online">> ), - spe_map:grant_additional(shr_player:get_id(Player)), + bnt_grant_land:attempt(shr_player:get_id(Player)), Player. diff --git a/src/special/spe_battle.erl b/src/special/spe_battle.erl deleted file mode 100644 index d907224..0000000 --- a/src/special/spe_battle.erl +++ /dev/null @@ -1,438 +0,0 @@ --module(spe_battle). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --export([generate/2, add_to/2]). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%%%% USED IDS COLLECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec update_ordset - ( - ordsets:ordset(any()), - ordsets:ordset(any()) - ) - -> ataxic:basic(). -update_ordset (New, Old) -> - AddedElements = ordsets:subtract(New, Old), - - ataxic:sequence - ( - lists:map - ( - fun (V) -> - ataxic:apply_function - ( - ordsets, - add_element, - [ - ataxic:constant(V), - ataxic:current_value() - ] - ) - end, - ordsets:to_list(AddedElements) - ) - ). - --spec get_equipment_ids - ( - orddict:orddict(non_neg_integer(), btl_character:type()) - ) - -> - { - ordsets:ordset(shr_portrait:id()), - ordsets:ordset(shr_weapon:id()), - ordsets:ordset(shr_armor:id()) - }. -get_equipment_ids (Characters) -> - { - UsedPortraitIDs, - UsedWeaponIDs, - UsedArmorIDs - } = - orddict:fold - ( - fun (_IX, Character, {UPIDs, UWIDs, UAIDs}) -> - {MWpID, SWpID} = btl_character:get_weapon_ids(Character), - AID = btl_character:get_armor_id(Character), - PID = btl_character:get_portrait_id(Character), - { - ordsets:add_element(PID, UPIDs), - ordsets:add_element(MWpID, ordsets:add_element(SWpID, UWIDs)), - ordsets:add_element(AID, UAIDs) - } - end, - {ordsets:new(), ordsets:new(), ordsets:new()}, - Characters - ), - - {UsedPortraitIDs, UsedWeaponIDs, UsedArmorIDs}. - - -%%%% ROSTERS HANDLING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec get_forbidden_locations - ( - btl_battle:type() - ) - -> ordsets:ordset(btl_location:type()). -get_forbidden_locations (Battle) -> - orddict:fold - ( - fun (_IX, Char, Set) -> - ordsets:add_element(btl_character:get_location(Char), Set) - end, - ordsets:new(), - btl_battle:get_characters(Battle) - ). - --spec find_random_location - ( - btl_map:type(), - ordsets:ordset(btl_location:type()) - ) - -> {btl_location:type(), shr_tile:type()}. -find_random_location (Map, ForbiddenLocations) -> - MapWidth = btl_map:get_width(Map), - MapHeight = btl_map:get_height(Map), - - Candidate = - { - shr_roll:between(0, (MapWidth - 1)), - shr_roll:between(0, (MapHeight - 1)) - }, - - IsForbidden = ordsets:is_element(Candidate, ForbiddenLocations), - - case IsForbidden of - true -> find_random_location(Map, ForbiddenLocations); - - _ -> - Tile = - shr_tile:from_class_id - ( - shr_tile:extract_main_class_id - ( - btl_map:get_tile_instance(Candidate, Map) - ) - ), - - case (shr_tile:get_cost(Tile) > 200) of - true -> find_random_location(Map, ForbiddenLocations); - - false -> {Candidate, Tile} - end - end. - --spec get_glyphs_omnimods (rst_character:type()) -> shr_omnimods:type(). -get_glyphs_omnimods (RosterChar) -> - GlyphBoardID = rst_character:get_glyph_board_id(RosterChar), - GlyphIDs = rst_character:get_glyph_ids(RosterChar), - GlyphBoard = shr_glyph_board:from_id(GlyphBoardID), - Glyphs = lists:map(fun shr_glyph:from_id/1, GlyphIDs), - case shr_glyph_board:get_omnimods_with_glyphs(Glyphs, GlyphBoard) of - {ok, Result} -> Result; - error -> shr_omnimods:new([], [], [], []) - end. - --spec create_character - ( - non_neg_integer(), - rst_character:type(), - btl_map:type(), - ordsets:ordset(btl_location:type()) - ) - -> btl_character:type(). -create_character (PlayerIX, RosterChar, Map, ForbiddenLocations) -> - {Location, Tile} = find_random_location(Map, ForbiddenLocations), - TileOmnimods = shr_tile:get_omnimods(Tile), - GlyphsOmnimods = get_glyphs_omnimods(RosterChar), - - Result = - btl_character:new - ( - PlayerIX, - rst_character:get_name(RosterChar), - optional, % TODO: link this to roster. - GlyphsOmnimods, - rst_character:get_portrait_id(RosterChar), - rst_character:get_weapon_ids(RosterChar), - rst_character:get_armor_id(RosterChar), - Location, - TileOmnimods - ), - - Result. - --spec handle_characters - ( - list({non_neg_integer(), rst_character:type()}), - non_neg_integer(), - btl_map:type(), - ordsets:ordset(btl_location:type()), - non_neg_integer(), - orddict:orddict(non_neg_integer(), btl_character:type()), - list(ataxic:basic()) - ) - -> - { - orddict:orddict(non_neg_integer(), btl_character:type()), - list(ataxic:basic()) - }. -handle_characters -( - [], - _PlayerIX, - _Map, - _UsedLocations, - _NextCharIX, - Characters, - AtaxicUpdates -) -> - {Characters, AtaxicUpdates}; -handle_characters -( - [{_, RosterCharacter}|NextRosterCharacters], - PlayerIX, - Map, - UsedLocations, - NextCharIX, - Characters, - AtaxicUpdates -) -> - NewCharacter = - create_character(PlayerIX, RosterCharacter, Map, UsedLocations), - - NewCharacters = orddict:store(NextCharIX, NewCharacter, Characters), - - NewUpdate = - ataxic:apply_function - ( - orddict, - store, - [ - ataxic:constant(NextCharIX), - ataxic:constant(NewCharacter), - ataxic:current_value() - ] - ), - - handle_characters - ( - NextRosterCharacters, - PlayerIX, - Map, - [btl_character:get_location(NewCharacter)|UsedLocations], - (NextCharIX + 1), - NewCharacters, - [NewUpdate|AtaxicUpdates] - ). - --spec handle_roster - ( - rst_roster:type(), - btl_map:type(), - ordsets:ordset(btl_location:type()), - btl_battle:type() - ) - -> {btl_battle:type(), ataxic:basic()}. -handle_roster -( - Roster, - Map, - UsedLocations, - Battle -) -> - Players = btl_battle:get_players(Battle), - NextPlayerIX = orddict:size(Players), - NewPlayer = btl_player:new(NextPlayerIX, 0, rst_roster:get_owner(Roster)), - NewPlayers = orddict:store(NextPlayerIX, NewPlayer, Players), - - Characters = btl_battle:get_characters(Battle), - {NewCharacters, CharactersUpdates} = - handle_characters - ( - orddict:to_list(rst_roster:get_characters(Roster)), - NextPlayerIX, - Map, - UsedLocations, - orddict:size(Characters), - Characters, - [] - ), - - NewBattle = - btl_battle:set_characters - ( - NewCharacters, - btl_battle:set_players - ( - NewPlayers, - Battle - ) - ), - - Update = - ataxic:sequence - ( - [ - ataxic:update_field - ( - btl_battle:get_players_field(), - ataxic:apply_function - ( - orddict, - store, - [ - ataxic:constant(NextPlayerIX), - ataxic:constant(NewPlayer), - ataxic:current_value() - ] - ) - ), - ataxic:update_field - ( - btl_battle:get_characters_field(), - ataxic:sequence(CharactersUpdates) - ) - ] - ), - - {NewBattle, Update}. - -%%%% BATTLE CREATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec generate_battle (map_map:type(), rst_roster:type()) -> btl_battle:type(). -generate_battle (Map, Roster) -> - TileInstances = map_map:get_tile_instances(Map), - BattleMap = - btl_map:from_instances_tuple - ( - map_map:get_width(Map), - map_map:get_height(Map), - TileInstances - ), - - Battle = btl_battle:new(BattleMap), - {S0Battle, _AtaxicUpdate} = - handle_roster(Roster, BattleMap, ordsets:new(), Battle), - - {UsedPortraitIDs, UsedWeaponIDs, UsedArmorIDs} = - get_equipment_ids(btl_battle:get_characters(S0Battle)), - - S1Battle = - btl_battle:set_used_portrait_ids - ( - UsedPortraitIDs, - btl_battle:set_used_weapon_ids - ( - UsedWeaponIDs, - btl_battle:set_used_armor_ids - ( - UsedArmorIDs, - S0Battle - ) - ) - ), - - S1Battle. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec generate (map_map:type(), rst_roster:type()) -> btl_battle:type(). -generate (Map, Roster) -> - Battle = generate_battle(Map, Roster), - Battle. - --spec add_to - ( - rst_roster:type(), - btl_battle:type() - ) - -> {btl_battle:type(), ataxic:basic()}. -add_to (Roster, Battle) -> - BattleMap = btl_battle:get_map(Battle), - ForbiddenLocations = get_forbidden_locations(Battle), - - {S0Battle, AtaxicUpdate} = - handle_roster - ( - Roster, - BattleMap, - ForbiddenLocations, - Battle - ), - - {UsedPortraitIDs, UsedWeaponIDs, UsedArmorIDs} = - get_equipment_ids(rst_roster:get_characters(Roster)), - - OldPortraitIDs = btl_battle:get_used_portrait_ids(Battle), - PortraitIDsUpdate = - ataxic:update_field - ( - btl_battle:get_used_portrait_ids_field(), - update_ordset(UsedPortraitIDs, OldPortraitIDs) - ), - - OldWeaponIDs = btl_battle:get_used_portrait_ids(Battle), - WeaponIDsUpdate = - ataxic:update_field - ( - btl_battle:get_used_weapon_ids_field(), - update_ordset(UsedWeaponIDs, OldWeaponIDs) - ), - - OldArmorIDs = btl_battle:get_used_armor_ids(Battle), - ArmorIDsUpdate = - ataxic:update_field - ( - btl_battle:get_used_armor_ids_field(), - update_ordset(UsedArmorIDs, OldArmorIDs) - ), - - S1Battle = - btl_battle:set_used_armor_ids - ( - ordsets:union(UsedArmorIDs, OldArmorIDs), - btl_battle:set_used_weapon_ids - ( - ordsets:union(UsedWeaponIDs, OldWeaponIDs), - btl_battle:set_used_portrait_ids - ( - ordsets:union(UsedPortraitIDs, OldPortraitIDs), - S0Battle - ) - ) - ), - - Update = - ataxic:sequence - ( - [ - ataxic:update_field - ( - btl_battle:get_used_portrait_ids_field(), - PortraitIDsUpdate - ), - ataxic:update_field - ( - btl_battle:get_used_weapon_ids_field(), - WeaponIDsUpdate - ), - ataxic:update_field - ( - btl_battle:get_used_armor_ids_field(), - ArmorIDsUpdate - ), - AtaxicUpdate - ] - ), - - {S1Battle, Update}. diff --git a/src/special/spe_map.erl b/src/special/spe_map.erl deleted file mode 100644 index afb5647..0000000 --- a/src/special/spe_map.erl +++ /dev/null @@ -1,58 +0,0 @@ --module(spe_map). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --export([grant_additional/1]). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec grant_additional (ataxia_id:type()) -> map_map:type(). -grant_additional (OwnerID) -> - Map = map_map:default(OwnerID), - - {ok, MapID} = - ataxia_client:add - ( - map_db, - ataxia_security:allow_only(ataxia_security:any()), - ataxia_security:allow_only(ataxia_security:user_from_id(OwnerID)), - Map - ), - - MapSummary = shr_map_summary:new(MapID, <<"Untitled Map">>), - - PlayerUpdateQueryOp = - ataxic:update_value - ( - ataxic:update_field - ( - shr_player:get_map_summaries_field(), - ataxic:apply_function - ( - lists, - append, - [ataxic:constant([MapSummary]), ataxic:current_value()] - ) - ) - ), - - ok = - ataxia_client:update - ( - player_db, - ataxia_security:admin(), - PlayerUpdateQueryOp, - OwnerID - ), - - Map. diff --git a/src/special/spe_player.erl b/src/special/spe_player.erl deleted file mode 100644 index 00086fd..0000000 --- a/src/special/spe_player.erl +++ /dev/null @@ -1,191 +0,0 @@ --module(spe_player). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --export([generate/3]). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec reserve_login (binary(), binary()) -> 'ok'. -reserve_login (UsernameLC, EmailLC) -> - ok = ataxia_client:reserve(login_db, UsernameLC), - ok = ataxia_client:reserve(login_db, EmailLC), - - ok. - --spec finalize_login (binary(), binary(), binary()) -> 'ok'. -finalize_login (UsernameLC, EmailLC, PlayerID) -> - LoginUpdateQueryOps = - ataxic:sequence_meta - ( - [ - ataxic:update_value(ataxic:constant(PlayerID)), - ataxic:update_read_permission - ( - ataxic:constant - ( - ataxia_security:allow_only - ( - ataxia_security:any() - ) - ) - ), - ataxic:update_write_permission - ( - ataxic:constant - ( - ataxia_security:allow_only - ( - ataxia_security:user_from_id(PlayerID) - ) - ) - ) - ] - ), - - ok = - ataxia_client:update - ( - login_db, - ataxia_security:janitor(), - LoginUpdateQueryOps, - UsernameLC - ), - - ok = - ataxia_client:update - ( - login_db, - ataxia_security:janitor(), - LoginUpdateQueryOps, - EmailLC - ), - - 'ok'. - --spec generate_inventory (ataxia_id:type()) -> ataxia_id:type(). -generate_inventory (PlayerID) -> - Inventory = shr_inventory:new(PlayerID), - - {ok, InventoryID} = - ataxia_client:add - ( - inventory_db, - ataxia_security:allow_only(ataxia_security:any()), - ataxia_security:allow_only(ataxia_security:user_from_id(PlayerID)), - Inventory - ), - - InventoryID. - --spec generate_roster (ataxia_id:type()) -> ataxia_id:type(). -generate_roster (PlayerID) -> - Roster = rst_roster:new(PlayerID), - {ok, RosterID} = - ataxia_client:add - ( - roster_db, - ataxia_security:allow_only(ataxia_security:any()), - ataxia_security:allow_only(ataxia_security:user_from_id(PlayerID)), - Roster - ), - - RosterID. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec generate (binary(), binary(), binary()) -> shr_player:type(). -generate (Username, Password, Email) -> - UsernameLC = string:lowercase(Username), - EmailLC = string:lowercase(Email), - - ok = reserve_login(UsernameLC, EmailLC), - - Player = shr_player:new(<<"">>, Username, Password, Email), - - JanitorOnlyPermission = - ataxia_security:allow_only(ataxia_security:janitor()), - - {ok, PlayerID} = - ataxia_client:add - ( - player_db, - JanitorOnlyPermission, - JanitorOnlyPermission, - Player - ), - - shr_janitor:new(player_db, PlayerID), - - InvID = generate_inventory(PlayerID), - RosterID = generate_roster(PlayerID), - - PlayerUpdateQueryOps = - ataxic:sequence_meta - ( - [ - ataxic:update_value - ( - ataxic:sequence - ( - [ - ataxic:update_field - ( - shr_player:get_id_field(), - ataxic:constant(PlayerID) - ), - ataxic:update_field - ( - shr_player:get_inventory_id_field(), - ataxic:constant(InvID) - ), - ataxic:update_field - ( - shr_player:get_roster_id_field(), - ataxic:constant(RosterID) - ) - ] - ) - ), - ataxic:update_read_permission - ( - ataxic:constant - ( - ataxia_security:allow_only(ataxia_security:any()) - ) - ), - ataxic:update_write_permission - ( - ataxic:constant - ( - ataxia_security:allow_only - ( - ataxia_security:user_from_id(PlayerID) - ) - ) - ) - ] - ), - - ok = finalize_login(UsernameLC, EmailLC, PlayerID), - - ok = - ataxia_client:update - ( - player_db, - ataxia_security:janitor(), - PlayerUpdateQueryOps, - PlayerID - ), - - - Result = shr_player:set_id(PlayerID, Player), - - Result. -- cgit v1.2.3-70-g09d2