a reverse-engineered Ragnarok Online server written in Erlang
* Actors can now see each other.
handle_cast({save_char, C}, Sessions) ->
log:debug("Saving character.",
[{character, C}]),
{atomic, ok} = mnesia:transaction(fun() -> mnesia:write(C) end),
{noreply, Sessions};
[<<16#6d>>,
[<<16#6d:16/little>>,
140:16/little, % TODO (Walk speed)
300:16/little, % TODO (Walk speed)
Version = case PacketVer of
20090901 ->
24;
_ ->
PacketVer
end,
PacketVer,
Version,
pack(16#86, {ActorID, {{FromX, FromY}, {ToX, ToY}}, Tick}) ->
pack(16#86, {ActorID, {FromX, FromY}, {ToX, ToY}, Tick}) ->
pack(16#87, {ActorID, {{FromX, FromY}, {ToX, ToY}}, Tick}) ->
pack(16#87, {{FromX, FromY}, {ToX, ToY}, Tick}) ->
ActorID:32/little,
(encode_move(FromX, FromY, ToX, ToY)):6/little-binary-unit:8,
Tick:32/little>>;
Tick:32/little,
(encode_move(FromX, FromY, ToX, ToY)):6/little-binary-unit:8>>;
pack(16#195, {Name, Party, Guild, Position}) ->
[<<16#195:16/little>>,
pack(16#195, {AccountID, Name, Party, Guild, Position}) ->
[<<16#195:16/little,
AccountID:32/little>>,
pack(16#1d7, Character) ->
<<16#1d7:16/little,
(Character#char.account_id):32/little,
2:8, % TODO: ?
(Character#char.view_weapon):16/little,
(Character#char.view_shield):16/little>>;
pack(16#22b, {A, C}) ->
Gender = if
A#account.gender == 0 ->
1;
true ->
0
end,
<<16#22b:16/little,
(A#account.id):32/little,
300:16/little, % TODO: Walk speed
0:16/little, % TODO: Effect 1
0:16/little, % TODO: Effect 2
0:16/little, % TODO: Effect 3
0:16, % Nothing
(C#char.job):16/little,
(C#char.hair_style):16/little,
(C#char.view_weapon):16/little,
(C#char.view_shield):16/little,
(C#char.view_head_bottom):16/little,
(C#char.view_head_top):16/little,
(C#char.view_head_middle):16/little,
(C#char.hair_colour):16/little,
(C#char.clothes_colour):16/little,
0:16/little, % TODO: Head direction (test this)
(C#char.guild_id):32/little,
(C#char.guild_id):16/little, % Guild emblem ID
(C#char.manner):16/little, % Manners
0:16/little, % Effect
0:16, % Nothing,
(C#char.karma):8, % Karma
Gender:8, % Gender
(encode_position(C#char.x, C#char.y, 0)):3/binary-unit:8,
5:8,
5:8,
(C#char.base_level):16/little>>;
pack(16#22c, {A, C, Tick}) ->
Gender = if
A#account.gender == 0 ->
1;
true ->
0
end,
<<16#22c:16/little,
0:8, % Nothing
(A#account.id):32/little,
300:16/little, % TODO: Walk speed
0:16/little, % TODO: Effect 1
0:16/little, % TODO: Effect 2
0:16/little, % TODO: Effect 3
0:16, % Nothing
(C#char.job):16/little,
(C#char.hair_style):16/little,
(C#char.view_weapon):16/little,
(C#char.view_shield):16/little,
(C#char.view_head_bottom):16/little,
Tick:32/little,
(C#char.view_head_top):16/little,
(C#char.view_head_middle):16/little,
(C#char.hair_colour):16/little,
(C#char.clothes_colour):16/little,
0:16/little, % TODO: Head direction (test this)
(C#char.guild_id):32/little,
(C#char.guild_id):16/little, % Guild emblem ID
(C#char.manner):16/little, % Manners
0:16/little, % Effect
0:16, % Nothing,
(C#char.karma):8, % Karma
Gender:8, % Gender
(encode_position(C#char.x, C#char.y, 0)):3/binary-unit:8,
5:8,
5:8,
0:8/unit:3, % Nothing
(C#char.base_level):16/little>>;
X = (XNum bsl 2) bor ((YNum band 16#C0) bsr 6),
Y = ((YNum band 16#3F) bsl 4) bor ((DNum band 16#F0) bsr 4),
X = (XNum bsl 2) bor ((YNum band 16#c0) bsr 6),
Y = ((YNum band 16#3F) bsl 4) bor ((DNum band 16#f0) bsr 4),
A = (X bsr 2) band 16#FF,
B = ((X bsl 6) bor ((Y bsr 4) band 16#3f)) band 16#FF,
C = ((Y bsl 4) bor (D band 16#0f)) band 16#FF,
A = (X bsr 2) band 16#ff,
B = ((X bsl 6) bor ((Y bsr 4) band 16#3f)) band 16#ff,
C = ((Y bsl 4) bor (D band 16#0f)) band 16#ff,
A = (X bsr 2) band 16#FF,
B = ((X bsl 6) bor ((X bsr 4) band 16#3f)) band 16#ff,
A = (X bsr 2) band 16#ff,
B = ((X bsl 6) bor ((Y bsr 4) band 16#3f)) band 16#ff,
{ok, FSM} = gen_server:call(State#zone_state.map_server,
{get_player, ActorID}),
{ActorID, FSM} = gen_server:call(State#zone_state.map_server,
{get_player, ActorID}),
valid(map_loaded, State) ->
valid(map_loaded, State = #zone_state{map_server = MapServer,
account = A,
char = C}) ->
gen_server:cast(MapServer,
{send_to_other_players,
C#char.id,
16#1d7,
C}),
gen_server:cast(MapServer,
{send_to_players_in_sight,
{C#char.x, C#char.y},
16#195,
{A#account.id, C#char.name, "Party Name", "Guild Name", "Tester"}}), % TODO
gen_server:cast(MapServer,
{send_to_other_players,
C#char.id,
16#22b,
{A, C}}),
gen_server:cast(MapServer,
{show_actors,
self()}),
valid({walk, {ToX, ToY, ToD}}, State = #zone_state{tcp = TCP,
map_server = MapServer,
account = #account{id = AccountID},
char = #char{id = CharacterID,
x = X,
y = Y}}) ->
log:debug("Received walk request.",
[{coords, {ToX, ToY, ToD}}]),
gen_server:cast(MapServer,
{send_to_other_players_in_sight,
{X, Y},
CharacterID,
16#86,
{AccountID, {X, Y}, {ToX, ToY}, zone_master:tick()}}),
TCP ! {16#87, {{X, Y}, {ToX, ToY}, zone_master:tick()}},
{next_state, valid, State#zone_state{char = (State#zone_state.char)#char{x = ToX, y = ToY}}};
char = #char{x = X, y = Y}}) ->
char = #char{id = CharacterID,
x = X,
y = Y}}) ->
CharacterID,
{next_state, StateName, StateData};
handle_event({show_to, FSM}, StateName, StateData = #zone_state{account = A,
char = C}) ->
gen_fsm:send_all_state_event(FSM,
{send_packet,
16#1d7,
C}),
gen_fsm:send_all_state_event(FSM,
{send_packet,
16#195,
{A#account.id, C#char.name, "Other Party Name", "Other Guild Name", "Other Tester"}}), % TODO
gen_fsm:send_all_state_event(FSM,
{send_packet,
16#22c,
{A, C, zone_master:tick()}}),
terminate(_Reason, _StateName, #zone_state{account = #account{id = AccountID}}) ->
terminate(_Reason, _StateName, #zone_state{account = #account{id = AccountID},
char = Character}) ->
{char, CharNode} = config:get_env(zone, server.char),
gen_server_tcp:cast({server, CharNode},
{save_char, Character}),
handle_cast({show_actors, Self}, State) ->
lists:foreach(fun({_ID, FSM}) ->
if
FSM == Self ->
log:error("Skipping self.");
true ->
gen_fsm:send_all_state_event(FSM,
{show_to,
Self})
end
end,
State#map_state.players),
{noreply, State};