egs/src/egs_char_select.erl

108 lines
5.0 KiB
Erlang

%% @author Loïc Hoguin <essen@dev-extend.eu>
%% @copyright 2010 Loïc Hoguin.
%% @doc Character selection callback module.
%%
%% This file is part of EGS.
%%
%% EGS is free software: you can redistribute it and/or modify
%% it under the terms of the GNU Affero General Public License as
%% published by the Free Software Foundation, either version 3 of the
%% License, or (at your option) any later version.
%%
%% EGS is distributed in the hope that it will be useful,
%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
%% GNU Affero General Public License for more details.
%%
%% You should have received a copy of the GNU Affero General Public License
%% along with EGS. If not, see <http://www.gnu.org/licenses/>.
-module(egs_char_select).
-export([keepalive/1, info/2, cast/3, raw/3, event/2]).
-include("include/records.hrl").
%% @doc Send a keepalive.
keepalive(#state{socket=Socket}) ->
psu_proto:send_keepalive(Socket).
%% @doc We don't expect any message here.
info(_Msg, _State) ->
ok.
%% @doc Nothing to broadcast.
cast(_Command, _Data, _State) ->
ok.
%% @doc Dismiss all raw commands with a log notice.
%% @todo Have a log event handler instead.
raw(Command, _Data, State) ->
io:format("~p (~p): dismissed command ~4.16.0b~n", [?MODULE, State#state.gid, Command]).
%% Events.
%% @doc Character screen selection request and delivery.
event(char_select_request, #state{gid=GID}) ->
Folder = egs_accounts:get_folder(GID),
psu_game:send_0d03(data_load(Folder, 0), data_load(Folder, 1), data_load(Folder, 2), data_load(Folder, 3));
%% @doc The options default to 0 for everything except brightness to 4.
%% @todo Don't forget to check for the character's name.
event({char_select_create, Slot, CharBin}, #state{gid=GID}) ->
%% check for valid character appearance
%~ << _Name:512, RaceID:8, GenderID:8, _TypeID:8, AppearanceBin:776/bits, _/bits >> = CharBin,
%~ Race = proplists:get_value(RaceID, [{0, human}, {1, newman}, {2, cast}, {3, beast}]),
%~ Gender = proplists:get_value(GenderID, [{0, male}, {1, female}]),
%~ Appearance = psu_appearance:binary_to_tuple(Race, AppearanceBin),
%~ psu_characters:validate_name(Name),
%~ psu_appearance:validate_char_create(Race, Gender, Appearance),
%% end of check, continue doing it wrong past that point for now
Folder = egs_accounts:get_folder(GID),
Dir = io_lib:format("save/~s", [Folder]),
File = io_lib:format("~s/~b-character", [Dir, Slot]),
_ = file:make_dir(Dir),
file:write_file(File, CharBin),
file:write_file(io_lib:format("~s.options", [File]), << 0:128, 4, 0:56 >>);
%% @doc Load the selected character into the game's default universe.
event({char_select_enter, Slot, _BackToPreviousField}, State=#state{gid=GID}) ->
{ok, User} = egs_user_model:read(GID),
Folder = egs_accounts:get_folder(GID),
[{status, 1}, {char, CharBin}, {options, OptionsBin}] = data_load(Folder, Slot),
<< Name:512/bits, RaceBin:8, GenderBin:8, ClassBin:8, AppearanceBin:776/bits, _/bits >> = CharBin,
Race = psu_characters:race_binary_to_atom(RaceBin),
Gender = psu_characters:gender_binary_to_atom(GenderBin),
Class = psu_characters:class_binary_to_atom(ClassBin),
Appearance = psu_appearance:binary_to_tuple(Race, AppearanceBin),
Options = psu_characters:options_binary_to_tuple(OptionsBin),
Character = #characters{slot=Slot, name=Name, race=Race, gender=Gender, class=Class, appearance=Appearance, options=Options}, % TODO: temporary set the slot here, won't be needed later
UniID = egs_universes:defaultid(),
egs_universes:enter(UniID),
User2 = User#egs_user_model{uni=UniID, character=Character, area=#psu_area{questid=1100000, zoneid=7, mapid=9202}, entryid=0},
egs_user_model:write(User2),
egs_user_model:item_add(GID, 16#11010000, #psu_special_item_variables{}),
egs_user_model:item_add(GID, 16#11020000, #psu_special_item_variables{}),
egs_user_model:item_add(GID, 16#11020100, #psu_special_item_variables{}),
egs_user_model:item_add(GID, 16#11020200, #psu_special_item_variables{}),
egs_user_model:item_add(GID, 16#01010900, #psu_striking_weapon_item_variables{current_pp=99, max_pp=100, element=#psu_element{type=1, percent=50}}),
egs_user_model:item_add(GID, 16#01010a00, #psu_striking_weapon_item_variables{current_pp=99, max_pp=100, element=#psu_element{type=2, percent=50}}),
egs_user_model:item_add(GID, 16#01010b00, #psu_striking_weapon_item_variables{current_pp=99, max_pp=100, element=#psu_element{type=3, percent=50}}),
{ok, User3} = egs_user_model:read(GID),
State2 = State#state{slot=Slot},
psu_game:char_load(User3, State2),
{ok, egs_game, State2}.
%% Internal.
%% @doc Load the given character's data.
%% @todo This function is temporary until we get permanent mnesia accounts.
data_load(Folder, Number) ->
Filename = io_lib:format("save/~s/~b-character", [Folder, Number]),
case file:read_file(Filename) of
{ok, Char} ->
{ok, Options} = file:read_file(io_lib:format("~s.options", [Filename])),
[{status, 1}, {char, Char}, {options, Options}];
{error, _Reason} ->
[{status, 0}, {char, << 0:2208 >>}]
end.