1/*
    2% NomicMUD: A MUD server written in Prolog
    3% Maintainer: Douglas Miles
    4% Dec 13, 2035
    5%
    6% Bits and pieces:
    7%
    8% LogicMOO, Inform7, FROLOG, Guncho, PrologMUD and Marty's Prolog Adventure Prototype
    9% 
   10% Copyright (C) 2004 Marty White under the GNU GPL 
   11% Sept 20,1999 - Douglas Miles
   12% July 10,1996 - John Eikenberry 
   13%
   14% Logicmoo Project changes:
   15%
   16% Main file.
   17%
   18*/
   19
   20:- dynamic(adv:wants_quit/3).   21:- dynamic(adv:console_tokens/2).   22
   23:- dynamic(adv:console_io_conn_history/7).   24:- dynamic(adv:console_io_player/3).   25:- volatile(adv:console_io_player/3).   26:- volatile(adv:console_io_conn_history/7).   27
   28:- use_module(library(socket)).   29
   30adv_server(Port) :-
   31 bugout1(adv_server(Port)),
   32 tcp_socket(ServerSocket), 
   33 tcp_setopt(ServerSocket, reuseaddr), 
   34 tcp_bind(ServerSocket, Port), 
   35 tcp_listen(ServerSocket, 5), 
   36 atom_concat('mu_', Port, Alias),
   37 thread_create(adv_server_loop(Port, ServerSocket), _, 
   38   [ alias(Alias)
   39   ]).
   40
   41peer_alias(Prefix,Peer, Host, Alias):- 
   42 (tcp_host_to_address(Host, Peer);Host=Peer),
   43 format(string(S),'~w@~w_',[Host,Prefix]),
   44 gensym(S,Alias),!.
   45
   46adv_server_loop(Prefix, ServerSocket) :-
   47 tcp_accept(ServerSocket, Slave, Peer), 
   48 tcp_open_socket(Slave, InStream, OutStream), 
   49 %set_stream(InStream, buffer(false)), 
   50 set_stream(InStream, close_on_exec(true)), 
   51 set_stream(OutStream, close_on_exec(true)), 
   52 set_stream(InStream, close_on_abort(true)), 
   53 set_stream(OutStream, close_on_abort(true)), 
   54 peer_alias(Prefix, Peer, Host, Alias), 
   55 ignore(catch(thread_create(
   56  adv_serve_client(InStream, OutStream, Host, Peer, Alias), 
   57  _, 
   58  [ alias(Alias)
   59  ]), 
   60  error(permission_error(create, thread, Alias), _), 
   61  fail)), 
   62 !, 
   63 adv_server_loop(Prefix, ServerSocket).
   64
   65setup_IO_props(InStream, OutStream):- 
   66 set_stream(InStream, tty(true)), 
   67 set_stream(OutStream, tty(true)), 
   68 % set_prolog_flag(tty_control, false), % JanW
   69 % set_prolog_flag(tty_control, true), % Dmiles
   70 current_prolog_flag(encoding, Enc), 
   71 set_stream(user_input, encoding(Enc)), 
   72 %set_stream(user_input, buffer(false)), 
   73 set_stream(user_output, encoding(Enc)), 
   74 %set_stream(user_error, encoding(Enc)), 
   75 set_stream(user_input, newline(detect)), 
   76 set_stream(user_output, newline(dos)), 
   77 set_stream(user_input, eof_action(eof_code)),!.
   78
   79adv_serve_client(InStream, OutStream, Host, Peer, Alias) :- 
   80 !, 
   81 thread_self(Id), 
   82
   83 set_prolog_IO(InStream, OutStream, OutStream),
   84 % set_stream(user_error, newline(dos)), 
   85 set_stream(OutStream, alias(user_error)), 
   86 set_stream(OutStream, alias(user_output)), 
   87
   88 setup_IO_props(InStream, OutStream),
   89
   90 set_stream(user_input, close_on_exec(false)),
   91 set_stream(user_input, close_on_abort(false)), 
   92 set_stream(user_output, close_on_exec(false)), 
   93 set_stream(user_output, close_on_abort(false)), 
   94 
   95 format(OutStream, 
   96  'Welcome to the SWI-Prolog Adventure Server!~n~q~n~n', 
   97  [adv_serve_client(Id,Alias,InStream,OutStream, Host, Peer)]), !, 
   98 call_cleanup(srv_catch(adventure_client_process(Id,Alias,InStream,OutStream, Host, Peer)), 
   99   adventure_client_cleanp(Id,Alias,InStream,OutStream)).
  100
  101srv_catch(Goal):- catch(once(call(call,Goal)),E,((notrace(bugout1(error_srv_catch(E,Goal))),!,fail))).
  102ignore_srv_catch(Goal):- ignore(srv_catch(Goal)).
  103tflush(OutStream):- ignore_srv_catch((flush_output(OutStream), ttyflush)).
  104
  105adventure_client_cleanp(Id,Alias,InStream,OutStream):- 
  106 ignore(notice_agent_discon(Id,Alias,InStream,OutStream)),
  107 retractall(adv:console_io_player(_,OutStream,_)),
  108 retractall(adv:console_io_player(InStream,_,_)),
  109 ignore_srv_catch(close(InStream)), 
  110 ignore_srv_catch(close(OutStream)),
  111 ignore_srv_catch(thread_detach(Id)).
  112
  113notice_agent_discon(Id,Alias,InStream,OutStream):- 
  114  once((
  115    adv:console_io_player(InStream,_,Agent);
  116    adv:console_io_player(_,OutStream,Agent);
  117    (adv:console_io_conn_history(_, Alias,_,_, _, _, Agent), \+ adv:console_io_player(_,_,Agent));
  118    (adv:console_io_conn_history(Id, _,_,_, _, _, Agent), \+ adv:console_io_player(_,_,Agent)))),
  119 assertz(adv:agent_discon(Agent)),
  120 bugout1((adv:agent_discon(Agent))),!.
  121
  122
  123:- dynamic(adv:peer_character/2).  124:- dynamic(adv:peer_agent/2).  125:- dynamic(adv:agent_character/2).  126:- dynamic(adv:agent_discon/1).  127
  128guess_previous_agent_0(_, Peer, Agent):- adv:peer_agent(Peer, Agent),!.
  129guess_previous_agent_0(Host, _, Agent):- adv:peer_agent(Host, Agent),!.
  130
  131guess_previous_agent(Host, Peer, Agent):- guess_previous_agent_0(Host, Peer, Agent),
  132 \+ adv:console_io_player(_, _, Agent).
  133
  134guess_previous_agent(_Host, _Peer, Agent):- gensym('telnet~',Agent).
  135
  136prompt_for_agent(Id,Alias,InStream,OutStream, Host, Peer, Agent,Name):- 
  137 guess_previous_agent(Host, Peer, Agent), 
  138 ignore(adv:agent_character(Agent,Name)),
  139 ignore(adv:peer_character(Peer,Name)),
  140 ignore(adv:peer_character(Host,Name)),
  141 (var(Name) -> format(OutStream, 'Enter your name [or leave bank for "~w"]: ', [Agent]), read_line_to_string(InStream,Name) ; true),
  142 accept_agent(Id,Alias,InStream,OutStream, Host, Peer, Agent,Name).
  143
  144aaifn(A):- clause(A,true)->true;asserta(A).
  145
  146accept_agent(Id,Alias,InStream,OutStream, Host, Peer, Agent,Name):-
  147 aaifn(adv:agent_character(Agent,Name)),
  148 aaifn(adv:peer_character(Peer,Name)),
  149 aaifn(adv:peer_character(Host,Name)),
  150 aaifn(adv:peer_agent(Peer,Agent)),
  151 aaifn(adv:peer_agent(Host,Agent)),
  152 %set_stream(user_output,alias(Agent)),
  153 asserta(adv:console_io_conn_history(Id,Alias,InStream,OutStream, Host, Peer, Agent)), 
  154   retractall(adv:console_io_player(InStream,_,_)),
  155   retractall(adv:console_io_player(_,OutStream,_)),
  156   retractall(adv:console_io_player(_,_,Agent)),
  157   asserta(adv:console_io_player(InStream,OutStream,Agent)),
  158 assertz(adv:agent_conn(Agent,Name,Alias,adventure_client_process(Id,Alias,InStream,OutStream, Host, Peer))),!.
  159
  160welcome_adv_tnet(OutStream):- 
  161  format(OutStream, '==============================================~n', []),
  162  format(OutStream, 'Welcome to Marty\'s Prolog Adventure Prototype~n', []),
  163  format(OutStream, '==============================================~n', []),
  164  !.
  165
  166adventure_client_process(Id,Alias,InStream,OutStream, Host, Peer):- 
  167 prompt_for_agent(Id,Alias,InStream,OutStream, Host, Peer, Agent,_Name),
  168 retractall(adv:wants_quit(_,InStream,_)),
  169 retractall(adv:wants_quit(Id,_,_)),
  170 welcome_adv_tnet(OutStream),
  171 overwrote_prompt(Agent),
  172 setup_console,
  173 repeat, 
  174 must(adv:console_io_player(InStream, OutStream, CurrentAgent)),
  175 adv_tlnet_readloop(Id, InStream, OutStream, CurrentAgent),
  176 needs_logout_p(Id, InStream, CurrentAgent), !. 
  177
  178needs_logout_p(Id, InStream, _Agent):-
  179  adv:wants_quit(Id, _, _);
  180  adv:wants_quit(_, InStream, _).
  181needs_logout_p(_, InStream, _Agent):-
  182  \+ adv:console_io_player(InStream, _, _).
  183needs_logout_p(_, InStream, Agent):-
  184  adv:wants_quit(_, _, Agent),
  185  \+ (( adv:console_io_player(InStream, _, Other), Other\==Agent)).
  186
  187adv_tlnet_readloop(Id, InStream, _OutStream, Agent):- 
  188 needs_logout_p(Id, InStream, Agent),
  189 sleep(0.1), !.
  190adv_tlnet_readloop(_Id, _InStream, OutStream, Agent):-  
  191 adv:console_tokens(Agent, _Words),
  192 tflush(OutStream),
  193 sleep(0.1), !.
  194adv_tlnet_readloop(_Id, InStream, OutStream, Agent):- 
  195 ensure_has_prompt(Agent),
  196 current_input(In), wait_for_input([In,InStream,user_input],Found,0.1), 
  197 Found==[], !,
  198 tflush(OutStream).
  199adv_tlnet_readloop(Id, InStream, OutStream, Agent):-
  200 read_line_to_tokens(Agent,InStream,[],Words),
  201 tflush(OutStream),
  202 must_det(adv_tlnet_words(Id, InStream, Agent, Words)),!.
  203
  204
  205adv_tlnet_words(Id, InStream, Agent, []):- 
  206  adv_tlnet_words( Id, InStream, Agent, [wait]).
  207adv_tlnet_words(Id, InStream, Agent, [quit]):- 
  208  adv_tlnet_words(Id, InStream, Agent, end_of_file).
  209adv_tlnet_words(Id, InStream, Agent, end_of_file):-
  210  asserta(adv:wants_quit(Id, InStream, Agent)),
  211  bugout3('~NTelent: ~q~n', [adv:wants_quit(Id, InStream, Agent)], telnet).
  212adv_tlnet_words(_Id, _InStream, _Agent, [prolog]):- !,
  213  prolog.  
  214adv_tlnet_words(Id, InStream, Agent, Words):- 
  215  assertz(adv:console_tokens(Agent, Words)),
  216  nop((bugout3('~NTelent: ~q~n', [adv_tlnet_words(Id, InStream, Agent, Words)], telnet))),
  217 % nop((adv:console_io_player(InStream,OutStream,Agent),format(OutStream, '~NYou: ~q~n', [adv:console_tokens(Agent, Words)]))), 
  218 !