egs/src/egs_users.erl

245 lines
8.4 KiB
Erlang
Raw Normal View History

%% @author Lo<4C>c Hoguin <essen@dev-extend.eu>
%% @copyright 2010-2011 Lo<4C>c Hoguin.
%% @doc Users handling.
%%
%% 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_users).
-behaviour(gen_server).
-export([start_link/0, stop/0, broadcast/2, broadcast_all/1, find_by_pid/1, set_zone/3]). %% API.
-export([read/1, select/1, write/1, delete/1, item_nth/2, item_add/3, item_qty_add/3,
shop_enter/2, shop_leave/1, shop_get/1, money_add/2]). %% Deprecated API.
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). %% gen_server.
-define(SERVER, ?MODULE).
-include("include/records.hrl").
2011-02-27 00:03:25 +08:00
-record(state, {
users = [] :: list({GID::integer(), #users{}})
}).
%% API.
-spec start_link() -> {ok, Pid::pid()}.
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
-spec stop() -> stopped.
stop() ->
gen_server:call(?SERVER, stop).
broadcast(Message, PlayersGID) ->
gen_server:cast(?SERVER, {broadcast, Message, PlayersGID}).
broadcast_all(Message) ->
gen_server:cast(?SERVER, {broadcast_all, Message}).
find_by_pid(Pid) ->
gen_server:call(?SERVER, {find_by_pid, Pid}).
set_zone(GID, ZonePid, LID) ->
gen_server:call(?SERVER, {set_zone, GID, ZonePid, LID}).
%% Deprecated API.
%% @spec read(ID) -> {ok, User} | {error, badarg}
read(ID) ->
gen_server:call(?SERVER, {read, ID}).
select(GIDsList) ->
gen_server:call(?SERVER, {select, GIDsList}).
%% @spec write(User) -> ok
write(User) ->
gen_server:call(?SERVER, {write, User}).
%% @spec delete(GID) -> ok
delete(GID) ->
gen_server:call(?SERVER, {delete, GID}).
item_nth(GID, ItemIndex) ->
gen_server:call(?SERVER, {item_nth, GID, ItemIndex}).
item_add(GID, ItemID, Variables) ->
gen_server:call(?SERVER, {item_add, GID, ItemID, Variables}).
%% @todo Consumable items.
item_qty_add(GID, ItemIndex, QuantityDiff) ->
gen_server:call(?SERVER, {item_qty_add, GID, ItemIndex, QuantityDiff}).
shop_enter(GID, ShopID) ->
gen_server:call(?SERVER, {shop_enter, GID, ShopID}).
shop_leave(GID) ->
gen_server:call(?SERVER, {shop_leave, GID}).
shop_get(GID) ->
gen_server:call(?SERVER, {shop_get, GID}).
money_add(GID, MoneyDiff) ->
gen_server:call(?SERVER, {money_add, GID, MoneyDiff}).
%% gen_server.
init([]) ->
2011-02-27 00:03:25 +08:00
{ok, #state{}}.
handle_call({find_by_pid, Pid}, _From, State) ->
2011-02-27 00:03:25 +08:00
[User] = [User || {_GID, User} <- State#state.users, User#users.pid =:= Pid],
{reply, User, State};
handle_call({set_zone, GID, ZonePid, LID}, _From, State) ->
2011-02-27 00:03:25 +08:00
{GID, User} = lists:keyfind(GID, 1, State#state.users),
Users2 = lists:delete({GID, User}, State#state.users),
{reply, ok, State#state{users=[{GID, User#users{zonepid=ZonePid, lid=LID}}|Users2]}};
handle_call({read, GID}, _From, State) ->
2011-02-27 00:03:25 +08:00
{GID, User} = lists:keyfind(GID, 1, State#state.users),
{reply, {ok, User}, State};
handle_call({select, UsersGID}, _From, State) ->
Users = [begin
2011-02-27 00:03:25 +08:00
{GID, User} = lists:keyfind(GID, 1, State#state.users),
User
end || GID <- UsersGID],
{reply, Users, State};
handle_call({write, User}, _From, State) ->
2011-02-27 00:03:25 +08:00
Users2 = lists:keydelete(User#users.gid, 1, State#state.users),
{reply, ok, State#state{users=[{User#users.gid, User}|Users2]}};
handle_call({delete, GID}, _From, State) ->
2011-02-27 00:03:25 +08:00
Users2 = lists:keydelete(GID, 1, State#state.users),
{reply, ok, State#state{users=Users2}};
handle_call({item_nth, GID, ItemIndex}, _From, State) ->
2011-02-27 00:03:25 +08:00
{GID, User} = lists:keyfind(GID, 1, State#state.users),
Item = lists:nth(ItemIndex + 1, (User#users.character)#characters.inventory),
{reply, Item, State};
handle_call({item_add, GID, ItemID, Variables}, _From, State) ->
2011-02-27 00:03:25 +08:00
{GID, User} = lists:keyfind(GID, 1, State#state.users),
Character = User#users.character,
Inventory = Character#characters.inventory,
Inventory2 = case Variables of
#psu_consumable_item_variables{quantity=Quantity} ->
#psu_item{data=#psu_consumable_item{max_quantity=MaxQuantity}} = egs_items_db:read(ItemID),
{ItemID, #psu_consumable_item_variables{quantity=Quantity2}} = case lists:keyfind(ItemID, 1, Inventory) of
false -> New = true, {ItemID, #psu_consumable_item_variables{quantity=0}};
Tuple -> New = false, Tuple
end,
Quantity3 = Quantity + Quantity2,
if Quantity3 =< MaxQuantity ->
lists:keystore(ItemID, 1, Inventory, {ItemID, #psu_consumable_item_variables{quantity=Quantity3}})
end;
#psu_trap_item_variables{quantity=Quantity} ->
#psu_item{data=#psu_trap_item{max_quantity=MaxQuantity}} = egs_items_db:read(ItemID),
{ItemID, #psu_trap_item_variables{quantity=Quantity2}} = case lists:keyfind(ItemID, 1, Inventory) of
false -> New = true, {ItemID, #psu_trap_item_variables{quantity=0}};
Tuple -> New = false, Tuple
end,
Quantity3 = Quantity + Quantity2,
if Quantity3 =< MaxQuantity ->
lists:keystore(ItemID, 1, Inventory, {ItemID, #psu_trap_item_variables{quantity=Quantity3}})
end;
_ ->
New = true,
if length(Inventory) < 60 ->
Inventory ++ [{ItemID, Variables}]
end
end,
Character2 = Character#characters{inventory=Inventory2},
2011-02-27 00:03:25 +08:00
Users2 = lists:keydelete(User#users.gid, 1, State#state.users),
State2 = State#state{users=[{GID, User#users{character=Character2}}|Users2]},
case New of
false -> {reply, 16#ffffffff, State2};
true -> {reply, length(Inventory2), State2}
end;
handle_call({item_qty_add, GID, ItemIndex, QuantityDiff}, _From, State) ->
2011-02-27 00:03:25 +08:00
{GID, User} = lists:keyfind(GID, 1, State#state.users),
Character = User#users.character,
Inventory = Character#characters.inventory,
{ItemID, Variables} = lists:nth(ItemIndex + 1, Inventory),
case Variables of
#psu_trap_item_variables{quantity=Quantity} ->
#psu_item{data=#psu_trap_item{max_quantity=MaxQuantity}} = egs_items_db:read(ItemID),
Quantity2 = Quantity + QuantityDiff,
if Quantity2 =:= 0 ->
Inventory2 = string:substr(Inventory, 1, ItemIndex) ++ string:substr(Inventory, ItemIndex + 2);
Quantity2 > 0, Quantity2 =< MaxQuantity ->
Variables2 = Variables#psu_trap_item_variables{quantity=Quantity2},
Inventory2 = string:substr(Inventory, 1, ItemIndex) ++ [{ItemID, Variables2}] ++ string:substr(Inventory, ItemIndex + 2)
end
end,
Character2 = Character#characters{inventory=Inventory2},
2011-02-27 00:03:25 +08:00
Users2 = lists:keydelete(User#users.gid, 1, State#state.users),
{reply, ok, State#state{users=[{GID, User#users{character=Character2}}|Users2]}};
handle_call({shop_enter, GID, ShopID}, _From, State) ->
2011-02-27 00:03:25 +08:00
{GID, User} = lists:keyfind(GID, 1, State#state.users),
Users2 = lists:delete({GID, User}, State#state.users),
{reply, ok, State#state{users=[{GID, User#users{shopid=ShopID}}|Users2]}};
handle_call({shop_leave, GID}, _From, State) ->
2011-02-27 00:03:25 +08:00
{GID, User} = lists:keyfind(GID, 1, State#state.users),
Users2 = lists:delete({GID, User}, State#state.users),
{reply, ok, State#state{users=[{GID, User#users{shopid=undefined}}|Users2]}};
handle_call({shop_get, GID}, _From, State) ->
2011-02-27 00:03:25 +08:00
{GID, User} = lists:keyfind(GID, 1, State#state.users),
{reply, User#users.shopid, State};
handle_call({money_add, GID, MoneyDiff}, _From, State) ->
2011-02-27 00:03:25 +08:00
{GID, User} = lists:keyfind(GID, 1, State#state.users),
Character = User#users.character,
Money = Character#characters.money + MoneyDiff,
if Money >= 0 ->
Character2 = Character#characters{money=Money},
2011-02-27 00:03:25 +08:00
Users2 = lists:delete({GID, User}, State#state.users),
{reply, ok, [{GID, User#users{character=Character2}}|Users2]}
end;
handle_call(stop, _From, State) ->
{stop, normal, stopped, State};
handle_call(_Request, _From, State) ->
{reply, ignored, State}.
handle_cast({broadcast, Message, PlayersGID}, State) ->
2011-02-27 00:03:25 +08:00
[begin {GID, #users{pid=Pid}} = lists:keyfind(GID, 1, State#state.users),
Pid ! Message
end || GID <- PlayersGID],
{noreply, State};
handle_cast({broadcast_all, Message}, State) ->
2011-02-27 00:03:25 +08:00
[Pid ! Message || {_GID, #users{pid=Pid}} <- State#state.users],
{noreply, State};
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.