2011-02-15 08:15:28 +08:00
|
|
|
|
%% @author Lo<4C>c Hoguin <essen@dev-extend.eu>
|
|
|
|
|
%% @copyright 2011 Lo<4C>c Hoguin.
|
|
|
|
|
%% @doc Zone handler.
|
|
|
|
|
%%
|
|
|
|
|
%% 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_zones).
|
|
|
|
|
-behaviour(gen_server).
|
|
|
|
|
|
2011-02-16 06:26:48 +08:00
|
|
|
|
-export([start_link/4, stop/1, setid/1]). %% API.
|
2011-02-15 08:15:28 +08:00
|
|
|
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). %% gen_server.
|
|
|
|
|
|
2011-02-16 06:26:48 +08:00
|
|
|
|
-record(state, {
|
2011-02-17 06:08:28 +08:00
|
|
|
|
setid = 0 :: integer(),
|
2011-02-18 03:12:45 +08:00
|
|
|
|
objects = [] :: list(),
|
|
|
|
|
indexes = [] :: list(),
|
|
|
|
|
targets = [] :: list()
|
2011-02-16 06:26:48 +08:00
|
|
|
|
}).
|
2011-02-15 08:15:28 +08:00
|
|
|
|
|
|
|
|
|
%% API.
|
|
|
|
|
|
2011-02-16 06:26:48 +08:00
|
|
|
|
%% @spec start_link(UniID, QuestID, ZoneID, ZoneData) -> {ok,Pid::pid()}
|
|
|
|
|
start_link(UniID, QuestID, ZoneID, ZoneData) ->
|
|
|
|
|
gen_server:start_link(?MODULE, [UniID, QuestID, ZoneID, ZoneData], []).
|
2011-02-15 08:15:28 +08:00
|
|
|
|
|
2011-02-16 06:26:48 +08:00
|
|
|
|
%% @spec stop(Pid) -> stopped
|
|
|
|
|
stop(Pid) ->
|
|
|
|
|
gen_server:call(Pid, stop).
|
|
|
|
|
|
|
|
|
|
setid(Pid) ->
|
|
|
|
|
gen_server:call(Pid, setid).
|
2011-02-15 08:15:28 +08:00
|
|
|
|
|
|
|
|
|
%% gen_server.
|
|
|
|
|
|
2011-02-16 06:26:48 +08:00
|
|
|
|
init([UniID, QuestID, ZoneID, ZoneData]) ->
|
|
|
|
|
SetID = rand_setid(proplists:get_value(sets, ZoneData, [100])),
|
2011-02-16 07:09:46 +08:00
|
|
|
|
Set = egs_quests_db:set(QuestID, ZoneID, SetID),
|
2011-02-17 06:08:28 +08:00
|
|
|
|
Objects = create_units(Set),
|
2011-02-18 03:12:45 +08:00
|
|
|
|
{Indexes, Targets} = index_objects(Objects),
|
|
|
|
|
{ok, #state{setid=SetID, objects=Objects, indexes=Indexes, targets=Targets}}.
|
2011-02-16 06:26:48 +08:00
|
|
|
|
|
|
|
|
|
handle_call(setid, _From, State) ->
|
|
|
|
|
{reply, State#state.setid, State};
|
2011-02-15 08:15:28 +08:00
|
|
|
|
|
|
|
|
|
handle_call(stop, _From, State) ->
|
|
|
|
|
{stop, normal, stopped, State};
|
|
|
|
|
|
|
|
|
|
handle_call(_Request, _From, State) ->
|
|
|
|
|
{reply, ignored, State}.
|
|
|
|
|
|
|
|
|
|
handle_cast(_Msg, State) ->
|
|
|
|
|
{noreply, State}.
|
|
|
|
|
|
|
|
|
|
handle_info(_Info, State) ->
|
|
|
|
|
{noreply, State}.
|
|
|
|
|
|
|
|
|
|
terminate(_Reason, _State) ->
|
|
|
|
|
ok.
|
|
|
|
|
|
|
|
|
|
code_change(_OldVsn, State, _Extra) ->
|
|
|
|
|
{ok, State}.
|
2011-02-16 06:26:48 +08:00
|
|
|
|
|
|
|
|
|
%% Internal.
|
|
|
|
|
|
|
|
|
|
%% @doc Return a random setid from a list of chances per set.
|
|
|
|
|
rand_setid(Sets) ->
|
|
|
|
|
N = crypto:rand_uniform(1, lists:sum(Sets)),
|
|
|
|
|
rand_setid(N, Sets, 0).
|
|
|
|
|
rand_setid(N, [Set|_Tail], I) when N < Set ->
|
|
|
|
|
I;
|
|
|
|
|
rand_setid(N, [Set|Tail], I) ->
|
|
|
|
|
rand_setid(N - Set, Tail, I + 1).
|
2011-02-17 06:08:28 +08:00
|
|
|
|
|
|
|
|
|
%% @doc Create the objects for all units in a set.
|
|
|
|
|
create_units(Set) ->
|
|
|
|
|
create_units(Set, 0, []).
|
|
|
|
|
create_units([], _MapNb, Acc) ->
|
|
|
|
|
lists:flatten(lists:reverse(Acc));
|
|
|
|
|
create_units([{{map, _MapID}, Groups}|Tail], MapNb, Acc) ->
|
|
|
|
|
MapObjects = create_groups(Groups, MapNb),
|
|
|
|
|
create_units(Tail, MapNb + 1, [MapObjects|Acc]).
|
|
|
|
|
|
|
|
|
|
%% @doc Create the objects for all groups in a unit.
|
|
|
|
|
create_groups(Groups, MapNb) ->
|
|
|
|
|
create_groups(Groups, MapNb, 0, []).
|
|
|
|
|
create_groups([], _MapNb, _GroupNb, Acc) ->
|
|
|
|
|
lists:flatten(lists:reverse(Acc));
|
|
|
|
|
create_groups([Objects|Tail], MapNb, GroupNb, Acc) ->
|
|
|
|
|
GroupObjects = create_objects(Objects, MapNb, GroupNb),
|
|
|
|
|
create_groups(Tail, MapNb, GroupNb + 1, [GroupObjects|Acc]).
|
|
|
|
|
|
|
|
|
|
%% @doc Create the given objects.
|
|
|
|
|
create_objects(Objects, MapNb, GroupNb) ->
|
|
|
|
|
create_objects(Objects, MapNb, GroupNb, 0, []).
|
|
|
|
|
create_objects([], _MapNb, _GroupNb, _ObjectNb, Acc) ->
|
|
|
|
|
lists:reverse(Acc);
|
|
|
|
|
create_objects([{ObjType, ObjPos, ObjRot, ObjParams}|Tail], MapNb, GroupNb, ObjectNb, Acc) ->
|
|
|
|
|
Object = create_object(ObjType, ObjPos, ObjRot, ObjParams),
|
|
|
|
|
create_objects(Tail, MapNb, GroupNb, ObjectNb + 1, [{{MapNb, GroupNb, ObjectNb}, Object}|Acc]).
|
|
|
|
|
|
|
|
|
|
%% @doc Create the given object.
|
2011-02-18 00:12:57 +08:00
|
|
|
|
create_object(Type, Pos, Rot, Params) ->
|
|
|
|
|
M = list_to_existing_atom(lists:flatten(["egs_obj_", atom_to_list(Type)])),
|
|
|
|
|
M:init(Pos, Rot, Params).
|
2011-02-18 03:12:45 +08:00
|
|
|
|
|
|
|
|
|
%% @doc Build a list of object indexes and targets based on the list of objects.
|
|
|
|
|
index_objects(Objects) ->
|
|
|
|
|
index_objects(Objects, 0, [], 1024, []).
|
|
|
|
|
index_objects([], _Index, IndexesAcc, _Target, TargetsAcc) ->
|
|
|
|
|
{lists:reverse(IndexesAcc), lists:reverse(TargetsAcc)};
|
|
|
|
|
index_objects([{Key, Object}|Tail], Index, IndexesAcc, Target, TargetsAcc) ->
|
|
|
|
|
M = element(1, Object),
|
|
|
|
|
Attrs = M:module_info(attributes),
|
|
|
|
|
{Index2, IndexesAcc2} = case lists:keyfind(is_indexed, 1, Attrs) of
|
|
|
|
|
{_, [true]} -> {Index + 1, [{Index, Key}|IndexesAcc]};
|
|
|
|
|
{_, [false]} -> {Index, IndexesAcc}
|
|
|
|
|
end,
|
|
|
|
|
{Target2, TargetsAcc2} = case lists:keyfind(is_target, 1, Attrs) of
|
|
|
|
|
{_, [true]} -> {Target + 1, [{Target, Key}|TargetsAcc]};
|
|
|
|
|
{_, [false]} -> {Target, TargetsAcc}
|
|
|
|
|
end,
|
|
|
|
|
index_objects(Tail, Index2, IndexesAcc2, Target2, TargetsAcc2).
|