History of World World began as a Citynight BBS tcon hack. The method i used for IPC made it easy to create the first verison of world...basically an avatar walking around the screen. Any number of people could connect and move around. Adding new features step by step was the method I used to expand World into something useablable. One of the first few details I dealt with was encapsulating raw input and file writing/reading/locking functions into separate files. Initially, it was just the raw input functions. But as I realized that I was not hacking the file functions any longer, decided to move them out as well. Eventually, I'd like more moved into the world_io.cc file such as all room load/save/print/etc functions. I don't know if I fixed ansi breaking before or after multiple room support, but it took a while to realize what was happening. Blocking variables took care of that. There are a few other hacked blocking variables such as "just_input" and "still_typing", but I feel those are self explanatory enough and are quite usefull. Adding support for Multiple rooms forced the mov file to not be a dumping gorund for raw ansi codes. The locking character (doors) convention was not so trivial. It forced me to rethink the map file structure. It now consists of the map data itself, a line of walkable characters, and lines representing special characters as 't' text, 'l' lockable, and 'j' jumpable. The map loader needed redesigning as well as the "MOVEMENT FILES" code. Adding future movement codes will be non-trivial. process killing handling Altered mov file to messages and not actual ansi codes Multiple maps reading files jumps talking/screaming (big complaint) roll call avatar over write Most of the above problems were easily solved by simplifying the code. The saying "remove constraints" has held true over and over in the World development. Discovered bug. A general purpose buffer was too small and ended up overwriting code in lprintf. I couldn't figure out why I was getting the spinny whenever I tried to [log on?]. It threw me since I had just made a change to main. It took quite a while to track down. In my desire to streamline the editing facilites, I ended up despensing with most of the hard coded functions. What I ended up with was an editing flag variable, regular movement, and a update_map_char command. By over simplifiying the code, I've actually allowed the user to custom design his or her own editing method. Another advantage to this is I was able to do away with a hack I had origninally added to the update_map_char which printed to the screen the change. Since update_map_char now updates the char that the avatar is standing on, there is on need to print it again! I said good by to 4 lines of code. I was also able to get rid of the original complex function in place of one that changes just one element in a map. The over simplification in map editing was a result of the type command. I figured someone would toggle a type flag and whatever was typed would be the character dropped. Movement would automatically be to the right and down. After tweeking the update char commands and movment function, i realized i was doing the same thing twice: asking for input and moving/placing a char. The only disadvantage to this is the few conditions that check for walkable chars, lockable chars, etc in the movement fucntion grew one variable in the condition statement. A command help facility was a trivial matter of adding an extra string to the parsing data structure and tweaking help to instead of print "no help for that command", to dumping the string to the command passed to it. The creation of the 'command' command which when used sends a message to the user forcing him to run a world command, allowed me to generalze even more character types. I was able to rid the map data structure of text and jumpaable chars. In place are cmd chars which tell the person to, as of now, dump or more a file and jump to a specific location. By changing the way the color library worked a day after creating it, I had to go back and edit most of the map functions which relied up on including the map data type itself, load/save (which did and still don't realy on selector functions. I also manually reconstructed each map file adapting the new color format so that those who did create maps wouldn't have to recolor them. I find myself using more and more the concepts learned in Scheme. After creating the linked list library, I've been converting one data strcture after another into a linked list. My latest conversion was the user's key binding structure which was initially an array of characters and an array of strings holding the corresponding commands. I now rely on the fact that generally, key and commands are stored one after another, so each one can be considered just one string. Since Scheme is list based, it just makes sense to store everyting as a list...of course, searching the list everytime someone issues a command (which is with every key press) isnt' ver efficient. But the initial method required a search of the bound keys in an array anyway. Having a hard time settup up security. Should all maintenance commands or system commands be based on a posession or password or a combination of both? Solution?: Convert important commands over to command items which can only be created by GOD anyway. Figured out how to implement text in world. Files will basically be map's but with infinite height. I had to rewrite the map data structure a bit and remove static map cell array sizes in place of dynamic allocation. I thought I would have to rewrite a few other functions, but that was not the case. I encapsulated quite well!!! (relying on the fact, of course, that char ** could be referenced still with ary[y][x]) First gdb bug fix! GDB kept reporting a fault in get_room_element. Used stack back trace to narrow the segfault error to when interrupt_main is called. If called during the middle of a redraw, the map data structure might be in the middle of being reloaded, which caused the room.cell pointer to be uninitialed. 0.6.08 Found bug messing around. While map display was off and a person moved off the map (blindly of course), the map was not reloaded, thus command char's we're not updated. 0.6.14 The sexiest thing I've done so far has been command objects! I've moved a lot of functionality away from the C code into World itself. The next sexiest thing was to turn the mode construct from a value based system into a bit field based one. It make the C code so much more simpler. I changed a call to a world C command to a normal C command, mainly, a call from create to append_object. Why? Create would parse the string replacing any $VAR with the proper alias. When passing objects within world between people, if an object's command included a $VAR, it would be evaluted by the receiver, which is bad. So I guess I made world more consistent by sticking with non-world C calls within the world code. [5/27/99: Reflecting, I belive one of the initial reasons for working on WSCHEME was to simplify message passing. I was having a hard time dealing with quasiquotation from scratch (as I was trying to explain in the last paragraphs] I might be able to clean up the mode construct a bit...i had to get messy for the value mode construct to work right (which it never did anyway). 0.7.0 WROTE WScheme from scratch thus implementing a somewhat REAL version of scheme. With this new tool, I hope World will become much more functional. We'll see. Solution for the MODE construct was to have a few boolean fields including WALK, MAIL, TYPE, EDIT, SYS, EXE and PARSE. WALK is normall set for normal users and put into PARSE mode to run internal commands. Since PARSE's boolean value is greater than the rest...a command's mode that is <= to the users current MODE is allowed to be evaluated. I gave different commands different modes (SYS, EXE...) which i might reduce to just WALK and PARSE since I can create objects that allow people access to the commands. IE: (wand global)(lambda x (talk 'global x)) [5/27/99: I seemed to have emulated the Citynight BBS construct of user levels. It was a brilliant construct, but extremely dead-end-ish. It almost became a nightmare making sure the user was in the correct mode since at various times they could be kicked out of one for another.] --------------------------------------- v2 ----------------------------------- Removed totally help facilities since it was so integrated with old command parsing construct Need to create a scheme primitive that reads input from keyboard and returns an atom of that string. Finally implemented talk loop. Only possible after implementing a true scheme interpreter within world. Forsee problems with object creation :( 1.0.01 The conversion of AWorld to BWorld is going very well. Line count is around 3700 including .scm files. By designing a true scheme interpreter and making it the engine of world...functionality should become limitless. The IPC is definately going to have to change. I forsee tremendous amounts of data being passed back and forth between process. I don't need a file to fill up within hours supporting this. A problem I have yet to deal with yet have touched upon is scheme expression passing. IE: (command emily "talk '(give me a hug)"). In otherwords, how can i pass symbols that are need to encapsulate what is being passed? I can make hacks within scheme to deal with this...but that is ugly. IE: (define space " ") (command emily "talk (word 'give space 'me space 'a space 'hug)") [5/27/99: Dont know what I was getting at at this juncture. I might have been forshadowing the need for quasiquote, which wasn't taught in CS61a.] 10/30/98 Dealt with the aforementioned problem by using scheme constructs rather than C. I was passing things around as strings, which was silly since all i had to do was pass them around as internalized scheme expressions. This allowed me to bind expressions with quotes in them. IE: (bind "z" '(talk "hello")) 3525 lines including scm files (!comments). Conversion going nicely. Spent a day dealing with the symbol/string scheme enhancement. Little things cropping up such as existing expressions assuming still that symbols/strings were the same. Also the exisiting boolean field representation for user mode got in the way of progress. (move 0) checked for the user in PARSE mode which doesn't exist. Next step is to deal with environment handling so as to limit what commands users are allowed to evaluate. This will replace the mode construct in WorldA. [5/27/99: to this day I have yet to come up with a clean? solution for this. More than likely I'll have to encapsulate all world functions inside a world- function-generator (that takes a passowrd?)] 10/7/98 Had to track down a few scheme parsing errors. Main one was with functions returning quotes lists of text. I implemented strings ie: "blah blah" and had to deal with those modifications. I also had to fix functions that I quickly hacked to deal with passed arguments. If no arguments were passed to the primitive...then a scheme error was triggered while attempting to get the car of null. 10/21/98 Got rid of world push/pop map constuct in favor of a jump primitive in wschee. Now puch/pop/dump can be done in wscheme! This is one of the first big deletions of world code! Moved completely over the keyboard binding construct to scheme! 10/27/98 Moved invnetory construct to wscheme. Problem to contend with is which environment to use when calling scheme(). This was a solution to the class construct. But how do I control that which is otherwise hidden form the scheme programmer? 10/28/98 Got rid of give construct in favor of commanding someone to create it then commanding the giver to delete it if successfull. MMMMmmmm! Realized the best way to deal with object passing, from user to user, is to rely on quoted expressions! Maybe even sense if an object is a string to string->atom it before using it. I'm going to have to totally re-write a lot of stuff now :( 10/29/98 Completed crude conversion of all llist dependent constructs. Last thing to go was map char cmd bindings. Need to have scheme deal with any type of character. Might have to re-evaluate the way ' works or implement \ TO DO SOLVED: primitive_command must somehow send the plain text of an atom I can just pass a string i suppose? which is then evaluated. but how can i send a quote within a quote? hmmm? (define space " ") (word 'long space 'live space 'donut) muhahah! Deal with quotes...doing a (room) breaks when a command has a quote in it :( 10/30/98 Bug fix: (move 0) checked that you were in parse mode. An ancient construct being disolved in favor of schems's environment construct. I forsee more bugs of this nature cropping up! 11/7/98 After a week getting tail-recursion to work correctly, I'm finally able to continue with World v2 development. Voice loop required a way to call interrupt_main. So i implemented that as the primitive FLUSH. 11/9/98 Conversion of maps to v2 is a pain in the but. I'll probabley decide to upload v2 without any users/maps and leave v1 up. Implemented twalk in wscheme. From this point on, most of v2 development will be within wscheme. BREAK catching doesn't work since raw mode is VERY raw. Need to cook it just a bit. ^C now caught...still see trouble with initial world login. Need to strip away bogus characters. 11/16/98 'BACKSPACE' deletes 1 char at a time during w_gets, while 'DELETE' deletes space delimited words. 11/18/98 Converted key bindings and map bindings to vector constructs...much faster now the movement response time. Next step: move all of the person/map constructs to wscheme constructs! The dumping of map bindings to self, although vector based, is somewhat slow when building a list of bindings to be displayed :( Scheme is slow slow slow! 11/18/98 Implemented vectors in wscheme allowing a few constructs that relied on accessing elements in a list to occur in O(n) time. This greatly sped up key and map binding access since those occur every move. Even though the concept of vectors, in my opinion, stray from the essence of scheme itself, it's still a valuabe tool when it comes to practical applications. The last 2 steps I would like to implement before uploading to the net are the conversion of map and person constructs to wscheme. To do this, i need to implement file I/O in wscheme. I still have yet to deal with environment handling. I might just disable direct access to the interpreter until this problem is resolved. 11/19/98 3863 lines. Removed some ancient string handling routines from the io library. Most of that stuff is functionality found within scheme anyway. The only thing i didn't remove was skip_white_space which the ipc still uses to skip over user names. 11/20/98 Converted the dumping of objects and key bindings to the user file from C to scheme functions. One hope with the new scheme map/person construct is breaking the binding limit of only viewable characters. This will allow for more types of char's to be displayed (assuming i incorporate char display types with each 256 character values) 11/22/98 Messing around with world.scm led me to some bad command expression. Mainly 'give' which was based on very ancient wscheme concepts concerning how objects were created. Initially objects were basically string descripts. Now, objects are actual scheme expressions (which can be converted to strings using my version of write called atom->string). 11/24/98 Converted person and map constructs to scheme. For a temporary implementation, i'll be relying on many of the existing C function to keep World working still. Removed C:primitive_display_person_stats 11/25/98 Removed c:primitive_load_key_bindings TODO: need to fix mapXXyy initialization i world.scm 11/28/98 Removed c:login, jump, redraw, who Created ipc-mov and ipc-msg primitives. Construct came about when i decided to attack converting c:who, since it simply wrote to the ipc file "w{avatar}{name}" Removed c:primitive_location/last_location/avatar/etc (i never used these since i jumped write into converting person/map constructs to wscheme. removed c:primitive_room (i'll deal with this later). I'm able to delete a lot of C functionality since most of it will be trivial to implement in wscheme. removed c:primitive_update_avatar Most of the conversion now is being done totally blind. This could lead to big bugs, but only within the logic since i'm hoping the new wscheme code will be bullet proof. I'm now working on making 'move' scheme'ish. I should make this one of the bastard wscheme/c hybrids since it will require as much speed as possible. It's recursive based (since it could call itself when evaluating a command character). My plan though is to convert everything to scheme, get the main world code to under 1000 lines then convert back the bullet-proof scheme expressions to buggy but fast C functions. 11/29/98 Converted successfully the movement ipc (doesn't handle anything else like roll call request and who requests). It's performance is better than I expected which means I might not have to convert much wscheme expressions back to C expressions. Little things like move_cursor are a big pain in the but since they are scattered all over the place and usually required terminal preference settings which have been converted to Scheme variables. 4157 .cc .h .scm line count. Converted half the interrupt_main construct (movement ipc) to wscheme. 11/30/98 Conversion of entire interrupt/ipc construct went well. The core of it was completed...i still have to work out the kinks like dealing with whispers (distance), 'command' commands, etc. But the basic framework is there. Converted c:command. Pretty trivial. Went ahead and made a private scheme expresson that send the ipc message directly to the recipiants message window (originally used only for the 'who' construct) For fun did a (talk map-cells). The ipc/interrupt construct was stuck in an endless loop. I need to work on reading files at the C level so that buffer overruns like this don't occur too much. Temporary solution was to make the input buffer length 8192. removed c:set_map_rows The scrolling map construct was buggy anyway (lots of ghosts) I'll rethink it later. Back to static sized maps for now. converted c:talk_color to fg+ and bg+. This should be a bit more clear to the user instead of cryptic commands like (text +f). 12/1/98 Converted c:toggle_edit_mode to ws:toggle-mode-edit. I'll be converting the mode construct to individual variables. Who cares about efficiency in scheme! Converted c:scroll_msg_window. This is still basically useless unless i use that kewl ansi lib. Removed w_color library. Forgot to remove it from the Makefile. Don't remove fluff from the Makefile very often! Converted successfully making dump-map a primitive. This should be the one and only function that went from C -> SCHEME -> C. It might also be a problem if i choose to alter the underlying vector construct in wscheme or the map construct in world.scm. Toggle display map conversion was not so trivial. It was using self to report the status of the map-display binding. So i converted c:self to wscheme as well. A bug croped up concerning hitting / to enter the scheme evaluator. It wasn't setting just-input...so everytime you entered a command directly, an extra line was displayed. Now c:w_gets will set just-input. Since w_gets should be the only thing that sets just-input, I realized later that i had to remove it everywhere else. Another place i found just-input begin set was in talk-general. This was causing any expression that called talk, global, self, etc directly to overwrite previous messages :( Converted c:drop and created a temporary new construct to change map attributes. It only takes characters, convertes them to the actual vector reference, and a valid map attribute string ie: "*147". This is enough to get map editing working. 3018 line count for *cc 3907 for *cc *scm *h Page-decipher in scheme was fun to rethink. Took a few seconds but was based on using a helper 3 times to vector-ref a string consisting every 3rd letter. Converted c:xchar Slow as a turd out of Donut's ass. We have a winner for another c->scheme->c conversion. 12/2/98 It came to my attention that I should not have all these special cases when dealing with the ipc. Instead...general scheme expressions should be sent. In an object oriented environment, this would basically be the entire expression that deicdes if it should update the current char and do so in the appropriate map or deal with the distance for talking/whispering/screaming. 12/3/98 Removed last reminates of w_person.cc and w_person.h. Now going through w_main.cc and cleaning it up. Found a residual temporary c->scheme hacks in world.scm. Write-bindings which took a vector and scheme file pointer and wrote them. I since then re-wrote it but never deleted the old version. Scheme gives you a lot of freedom...which is why that went unchecked. Write-map and write-person created. My nightmare come true is here. While doing scheme stuff...interrupt's that cause more scheme stuff to occur are conflicting. Basically, i'll need some sort of semaphore to prevent scheme expressions from evaluating until others are done...strange concept. 12/4/98 Focusing now on the movment construct. It's a bit more streamlined than the C version since i realized i could get away with move calling itself if and only if move is the only thing that can call itself. I created walk which calls move when then calls itself it it needs to. Doing this separates the users concept of walking and the interpreters since both rely on the previous position in different ways. A users last position is what he appears to have been at. World's last position is exactly the last position the user was before anything else is evlauted. This is required if (move 0) is to work correctly, ie: person move's into a wall..the wall sends them back. As far as the user is concerned...they didnt' move since walk keeps a local copy of the last position. This also keeps the ipc clean since unneeded position changes are not sent to everyone else. Implemented reload-key. This was trivial in that i just sent read-key-bindings! an input file pointer to world.key. Movement ipc is complete except for scrolling (panning) maps. The implementation is dog slow. I'm going to try and implement the compile construct in wscheme in the hops of speeding things up a bit. Besides that, it is basically ready for upload as a VERY fancy chat utility. I still have to implement environment hiding. Found another residual wscheme construct...save-all-objects. It sill used the o'(whatever) mechanism of storing objects in a user file. 12/6/98 Oops! The map number construct was based on hexedecimal values. Must now rethink how i deal with numbers in scheme. Do i write special hex mathmatical operators or make the base number construct hex (which i'd prefer). 12/9/98 Moved main-eval-loop from a C construct to scheme. Worked great except I also converted c:logout to scheme and had it take a string representing the *** or !!! padding around the logout message. Unfortunately the user binding for ^Q was just plain old (logout) so it wasn't failing when calling logout and the evaluator got stuck in some strange endless loop :( 12/10/98 First time at multiple users. Very slow with only 3 or 4 people walking around. Might have to convert more than a few things back to C for performance. Implemented change-password Don't need to implement change-map-password since the only thing doing that will be primitives or root. wc w_*cc w_*h world.scm -> 3339 12/24/98 Major redesing of wscheme. Mainly to implement GC. Latest make seems to work ok on the current .scm files. 12/25/98 Current implementation is still not handling interrupts well (duh). Solution: Hmmm. a few blocking vars that will handle the interrupt when it deems OK. 12/27/98 A few little user functions are being implemented like text fg/bg color inc, edit char fg/bg color inc/dec etc. Seemed to have fiexed the interrupt blocking problem by using a blocking var within the GC routine since that would be the only function that could leave a pair in an unstable state. Other functions that mutate pairs need not be blocked since the mutation is instantaneous. Talking with a few people on #lisp inlightened me to the fact that most C compilers will also handle tail recursion. Need to look into this for it might clean up the C code for wscheme. 3786: wc *cc *h *scm world.key 12/28/98 Found ESCx2 bug. All i did was use a different timer with setitimer. This allowed me to use select to wait until someting happened to stdin. Unfortunatley hitting page up/down sent all the char's before select could sense anything...so it was still useless. I just spend an hour or so rethinking it. Used fseek to look ahead one char. The wait_for_keypress is now much simpler and doens't use the any timer functions. At least now you can hit ESC once. Researching ncurses to see how they implemented it. To complicated. 12/29/98 Interrupt catching while evaluating is now working correctly. Main problem, which might have corrected the problem earlier, was the return value was not initialied to a valid atom. So chances are the evaluation process would try to print the final result which would be NULL. now ret = make_null (); During world, I had to put a call to scheme:world-eval-loop since ^C would stop the main world evaluation process. Also had to reset block_interrupt since world-eval-loop mutates the value and we'd never set the scheme expression would never get a chance to reset it. Talk/Scream/Whisper/Global/Private now behave as in v1. Before they were all pretty much global since i considered it a fluff item anyway. Had a hard time getting scream to work when i realized that the map location is still represented as 3 packed hex numbers :( I should deal with that i think. 12/31/98 Implemented, for fun, fart and avatar case change while walking (to simulate the up and down motion of someone walking). I should look into the scheme ` construct since it would probabley prevent me from having to create new expressions using multiple list commands since some of the values in the command expressions i'm sending are the senders values. IE: (command '* '(jump {my_location})) 1/1/99 Messing around with the Flip a Coin game realized I need to seed the rnd function otherwise people could amass large quantities of coins. Realized this while working on quasiquote. 1/10/99 A lot of work so far has been working out bugs. Did create a hackish letter object. Can be picked up, used, droped and given to others. For some reason, going into debug mode caused repetative "'s to appear. Doug found it then emily. I didn't know the cause at first. A few other bugs found recently included the assumptions that maps would be exactly 80x25 (replaced 80 with MapWidht in a few places. GC had to be called if I was relying on a write-file pointer to be closed, especially in write-map. I should implement close-input/ output-port. ^C seems to be working ok as well. Created jump chars that forced the user in a loop and was able to break out of it somewhat cleanly. User still must redraw screen. 2/3/99 Found a bug. The background of anyone walking is the BG of your avatar! 3/9/99 Slowly hacking in v1 features into v2. time implemented so users will be able to report their idle time better. jump-to implemented after quasiquote was implemented. 4/8/99 Removed duplicate primitive_eval in scheme and mainscheme. Also, removed separate primitive_eval_wtge/stge (since they both did the same thing save for the passed environment) TO DO: (talk (atom->string person)) buffer over-run somewhere!!! ear-muffs environment hiding INTERESTING: sigaction 4/19/99 Put back primitve_eval_wtge since it was using env of whatever was calling it in the scheme world. I lost sight of the evaluation process there for a few weeks :( hehe. Finally converted query_terminal to a primitive. Will be nice having world auto-sense terminal settings again. 4/7/99 Got to see Josh's display on world and noticed it was a bit messed up. I just happened to be messing with it and noticed I could reproduce the map drawing flaw when hitting [ and ] (change bg color of current char). I think it's a lag issue..don't knwo what to fix in world but since most people use the cursor keys to move I've disabled the binding for [ since it might be sent by itself due to lag, causing a broken escape sequence to be sent somehow. The error on his display hinted at the ESC not being read by his terminal (or maybe me not sending it?) Cleaned up a bit of general stuff such as names that have spaces (break's the ipc) and avatar's that don't shift case well. 5/19/99 One hinderance of World's acceptance might be the fact that the ascii display is somewhat discrete. In a non graphical mud, the imagination creates a fluid environment and a more life-like world. First person 3d seems to be the the only way to simulate the world. Although anything computer related is discrete, we can only perceive this to a certain level. Proff of this was found in Doug's desire to have a multi-character-sized object. I explained that the ascii display was not representative of the internals of the engine rather that I choose ascii as a simple interface to the internals. The potential of world can't be shown through such a primitive interface...although therein lyes the power of doing almost anything very easily. 5/27/99 wc w_* -> 3433 Implemented a cheesy combat system. Created a procedure that takes a user name (attacker) and position (of the atacker). Needless to say attacking is done on the same spot. I plan on changing it so that it takes 2 functions. One that figures out how the person is being attacked and the other how damage is to be applied. 5/28/99 Implemented reset-mov/msg. Fun to watch history repeat itself. Would be nice if while it was doing it's thing I could still move around. Limitation of the IPC prevents this of course. 5/30/99 Redesigning map construct from individual maps to one big map broken up into char-only map segments. 5/31/99 All map Z maps will share a common attribute file that contains the map width, height, colors, and bindings (ie: wmap80 for the wmap80yyxx maps). Removed MapRows construct (used during v1 for scrolling maps to set a local vertical scrolling window size, 3rd line 4th parameter of the user file). A lot of work done on the load-map construct. Split it into 2: one that reads the new common plane attr file and one that reads maps. Changs are creating a platform that needs less config files than before. Even though scheme is a nice language, I'm spending quite a bit of time hacking this new map construct. Biggest problem is wscheme not reporting errors very nice. It would be nice if it could display the nearest binding in question. Maybe it should dump the top of the stack? Doh. I must have broken recently (while implementing references) the message and symbol that is displayed when a binding can't be found. This might have just saved me a few hours today :( Removed ipc-send-reload construct since I can just command people to do so. There are quite a few internalized constructs I can make general i suppose. The 2 i can get rid of in the movement construct are 'who' and 'roll-call' i belive. Removed ipc-send-who in favor of a global command to everyone. 5/2/99 Switched wscheme over to a purley base 16 number interpreter. I like it. Reduced new map char size from 4 hex digits (2020) to 3 (020). This I did to help speed up writing the plane attribute file. Need to decide when to load the plane-attribute file. Not everytime one moves from map to map of course. If someone decides to load it while it's being written to, a core dump results. Don't want to busy wait on the file since there might be stuck as a 0 length file. Hmm... 5/5/99 Going to also redesign the construct for map loation from ZZYYXXyyxx to ZZZZYYYYXXXX which will be a location in the world as a whole. 6/6/6 Completed, mostly, major over haul on internal map location abstraction. A bug has cropped up concerning or (not behaving!?). Wasn't really or, It was my use of 3 strings representing the 3 states of location (now, last, home). By using set! i was just pointing two symbols to the same string :(. So substring-set! now has another purpose, to copy a string from one space to another (there is an officla implementation which I should be using in the scheme spec). I feel world is in a pretty good stage 2++ to upload. Just need to fix a few minor things such as user file loading and key bindings. And make sure map editing works ok (might have to implement file locking?). A few functions, that are by spec supposed to return unspecified, were returning useless things like #f or #t. I replaced most of those with SNULL. Re-implemented the abstraction. Was easier after I gained a sense of what it was I really needed to abstract. Now emulating map scrolling is as easy as 2 loops over a global location value. It also meshes quite nicely with the persistant (still using it) map construct. 6/9/99 Among many of the abstrctions i'm forced to deal with after making wscheme more like normal scheme is that of strings vs. numbers. Originally, strings and numbers were the same. Now, internally, they are very different. At the same time, i'm hoping it will make things a bit more efficient since I'm not always having to parse numbers before evaluating them in mathmatical and predicate expressions. Attribute color, for cells as well as text, was once a 3 char array, now it's an actual number from 0 to 255 (representing the 255 possible colors a text char can have). If I make the abstraction correct, this will work for any color tuple ie: high/true color maps. 6/10/99 Another below the abstraction change will be with external cell attribute description. It will be, for now, a hex 4-tuple. The first byte representing the ansi char and the 2nd the ansi color. Kewl idea. Plan to generalize the world size to 1x10^18 (hex of course) ie: wmap000011110000111100001111. Each map will be able to be from 1x1 -> ffffffffxffffffff which is 10^18*10^10 = 10^28 = 16^40 (base 10) There will be 6 main vars (Mapz Mapy Mapx Locz Locy Locx) pertaining to the world location (which map in the 3d world) and map location (which cell on a 2d map) 6/17/99 Removed LocHome global var in favor of an object representing home location. Makes more sense to move most of these global concepts to objects since objects are automatically saved when the user is saved. Current wmap construct: wmap : map Z coordinate machine name machine port wmapX : xxx cell xx cell ascii value xx cell ansi value wmapX-X-X : map-height count of \n delimeted (map-width count of cell's xxx) 6/22/99 Problem still with word and string-append not doing nice things. Needed to add an atom->string to part of the login process (for those who entered the incorrect password of an existing user) since Name ended up being a symbol and not a string (after space removal and such). 7/1/99 First 3d construct bug. Default position for joining was z=1 in a map so rollcall wasn't being dealt with (since most people were at z=0 in the map). Had this been an actual 3d interface, people would have been walking on peoples heads. 7/4/99 Reimplemented once again the wmap construct. It is now an external representation of a vector containing the cell values. This has now lifted the restriction of cells being a particular bit size. In doing this i had to impement (write fp) which i did before in a hackish way with (write-string ( atom->string x)) Since wscheme is pretty efficient, i've foregone relying on C's speed for dump- map. I now have quite a bit more flexibility when it comes to rendering maps in world. For now, scrolling is simulated when one moves up or down by redrawing the screen via insertion of rows at the top or bottom. A comment i had just before the C dump_map read: // FIRST C -> SCHEME -> C CONSTRUCT Funny that now it's back to scheme again. wc w_* {world files}.scm -> 4638 7/10/99 Found bug with movement function. If a cell has a bad movement binding then the person will get stuck (doesnt' move anywhere but tries and evaluate the cells' binding, repeat). When someone logs in but doesn't type their name for a while, then the ipc will finally do it's thing for however long it's been. This could be an issue as messages will then scroll by and people will move all over the place confusing the new user :( 7/13/99 Hoping to deal with issues I put on the back burner, namely annoying little things like the interrupt always sending esc sequences and not being able to see people talk til your done typing. During the process removed a lot of the C coded IO functions like wgets (which now relies on primitives raw-gets, raw-getsh, and raw-getchar). Able to implement a real working talk-loop since now I handle any sort of interrupt during a getstring. Makes for a smoother interface. The key was getting the right escape sequencing so that nothing overworte one another. I'd like to have abstracted a general window class, but this will do for now. I belive the only time i'd want to erase what a user just inputs is talking. Everytyhing should remain for future reference ie / or special cells that requrire input. 7/14/99 Converted C:dump to scheme 7/15/99 There are a lot of C primitives and consturct I should move over to scheme. One being the ipc (should be able to convert thatover to my specialized io_port construct). Thu Aug 12 23:43:28 1999 Updated page-decipher a while back. Also noticed a bug in 'jump'. When a map cell jumps you somewhere else after a cell moved you back the jump is bogus ie (walk into a wall then walk on the jump char). Wed Aug 18 02:07:28 1999 Updated save-person so that it didnt' use helper functions and instead used for-each and loopn (a bit more scheemish) This allowed me to finally used display and write in usefull settings. Sun Aug 22 16:12:43 1999 While walking around the main map ran over a char that tried to set-backspace, an old hack trying to allow people to set the backspace character. I instead allowed for both backspace and delete to behave the same when entering text along with ctrl-u and ctrl-y (delete word). Sat Aug 28 12:13:55 1999 Spend 2 days dealing with thread concept. Major bug in world implementation was not setting *ret to return value in world primitives. WSCheme was perfect, so was difficult to track down. Ultimatly realized after debuging: (display (word 1 (raw-gets) 1)) and noticing that raw-gets was returning nothing or null. Sun Oct 24 16:49:15 1999 Copied over the current state of world and ran into a few hitches. Main one is ncurses isn't querying the correct terminal size (when accesed via scrt). It seems to do ok from a linux console. Otherwise it's stuck at 24x80. A workaround with the idiosyncrasies of ncurses was to use it only to query the terminal size. After that i resort to my normal raw/cooked mode routines. Second was not copying over the latest scm fiels. It would seem i made write compliant so that it can also take a file-pointer and output to taht instead. Before i had written write-string or something like that so a few things were broken. Currently, the only major bug that i'm ignoring is a forced 'talk' will clear the row the avatar is currently on. I belive it has something to do with the original construct that assumed after (or before) a talk the cursor will be at the bottom, thus clear it before printing again. Sun Dec 12 01:31:03 1999 Finally got terminal size sensing working. Had to snarf the code from the utiliti 'stty'. It's based on ioctl which sets some win structure. Implemented a 'viewport' type thing. Now you can specify the map size (it defaults to the width of the terminal by the PortRows the user set!'s). It was pretty straight forward implemnting, just had to create a few more 'location' functions, specifically ones that check < and > on the y and x axis of location objects. A viewport is just another location object. It's width and height are bound to PortCols and PortRows. A problem that cropped up was the default buffer size for the load function. It was set to 32768 which caused world to just exit. Took a while to figure out that it was a size issue when loading worldefs.scm since near the end of the file expressions weren't being evaluated. I remember having this issue before. Sat Dec 18 18:35:50 1999 Running into internal/external representation issues. Much of the logic now is centered around a 'global' (z y x) coordinate system. It was built around the notion of screens, each screen being itself a 3 dimenstional block of characters, and screens in a 3 dimensional block (of screens). This 6d mapping vs a global 3d mapping needs to be abstracted. I've had plenty of practice with this dealing with BOOEE. The internal/external structure of an event (MFO: meta-form-object in v2) was abstracted with a single function that accepted any form of the object and returned any other for. Sun Dec 26 16:00:51 1999 Successfully converted ipc from a compiled command construct to just sending external scheme expression. It now only has to parse scheme rather than interpret cryptic sets of characters (which was a spin-off from the original ipc which sent map coordinates as groups of hex digits and avatar/name values in specific fields). Mon Dec 27 02:36:42 1999 Since the external representation of things in world are just schem expressions, i was able to remove a loc-ext and ext-loc. I want to now focus on a way of dealing with location as a world based coordinate and a world/map based. Wed Dec 29 02:23:33 1999 Successfully converted location construct in favor of a global coordinate bias. Only had to track down a little bug relating to loc-set{zyx}! so that it returned the mutated vector. Other than that the abstraction held perfectly (save for a few function name changes that :%s//g could handle) Mon Jun 5 23:50:43 /etc/localtime 2000 Spending much of my time these days on wscheme. After picking out the most interesting articles in my collection of Game developer, I came across "TinyMUSH: Implementing a MUD". It touches on this MUDS' interworkings and initial user login. Makes references to fantasy authors used by many mud developers: J.R.R. Tolkein -- Anne McCaffery -- C.S. Lewis Mon Mar 19 16:46:02 PST 2001 Discovered an issue that might have caused trouble in the past. If the escape code (save/restore) occurs when the cursor is on the last column (ready to newline, but not yet since a character hasn't been sent so it won't newline till it needs to) then the newline isn't sent on the first character. Tue Mar 27 08:14:25 /etc/localtime 2001 World idea: (have had many in the past, should log them here). Have a bunch of spirits be chracters in stories or plays. Just like the holodeck, world visitors won't know the difference between the real-world or the 'holodeck' world in world. Hehe. I see it as an educational tool or even a new form of media to get those who would otherwise shy away from books (read 'me') involved in the classics. The oddysey would be krad! Perhaps that will be my first attempt. First chapter of The Iliad. Thu Jun 7 18:22:25 /etc/localtime 2001 Finally here! Working on World itself! Or at least the next incarnation of it. V3 to be exact. Currently redesigning the map abstraction a bit. I think I'll have each process handle display of the map and a spirit the mutation of it. Found a bug in C code while looking for another bug. Noticed I wasn't creating a big enough dirty object in new_port. Reason being initially I didn't keep the file name and mode string, just the FILE pointer. I found it while trying to write parse-map-plane which it couldn't find since I didn't rename it to just 80 from wmap80. I'm moving all map files to the directory map so I'm stripping wmap from all map data file names. Fri Jun 8 08:26:05 /etc/localtime 2001 Figured out a simple map file caching system. Just store them in a two dimensional array where the actual content is based on a modulus of it's map x,y location. IE: 80-79-89 80-79-80 80-79-81 80-80-89 80-80-80 80-80-81 80-81-89 80-81-80 80-81-81 So if map 80-80-80 is needed, it's there, but if map 80-82-80 is needed, then it needs to be loaded and the array mutated to reflect it. IE: 80-79-89 *80-82-80 80-79-81 80-80-89 80-80-80 80-80-81 80-81-89 80-81-80 80-81-81 Very slick! Realized this in bed this morning. Heh heh. Unbelievable! Frist attempt at implementing map cache system worked! Took only a few minutes. I have 3 vectors which store the cached x and y map coordinate and the corresponding map cells. The index becomes (+ (modulo x 3) (* (modulo y 3) 3)). Checking is trivial and updating is trivial. Problem when persons coordinate goes negative. The 1st location is -1, rather than 0, in this negative land. Would be nice if i could somehow work in a -0 into the math to keep everything consistent otherwise I'll have to put checks everywhere for a negative location and always add 1 to the math while putting a - in front of the 0 when I create the map file name. Weird. Sun Jun 10 12:04:19 /etc/localtime 2001 What if I had multiple IPC files that could be connected, disconnected at random? This would allow for separate talking, movement, and command channels. I like this idea! Realized I didn't need to create the components of the ansi string for each cell. Instead I could just index a vector of strings based on the ansi fore/ background value. I COULD do the same for characters, since characters in wscheme ARE strings. It would be a huge array. I'd be re-implementing integer->char. Hmm. Perhaps I should do it at the C level? No, cause I'd need 256 string constants. Which is no big deal I guess? Hmm. Maybe later. Tue Jun 12 20:29:31 /etc/localtime 2001 Archived: v3-6.3.tgz Going to completley redesign the core world graphic engine. Instead of being two separate ideas, the static map and independent avatars, I'm going to make everything an object in the map. Avatars will be just like map cells, using the current nomenclature. Movement will be applied to objects, not sure yet how to specify objects. But for now the users will keep track of their avatar's location. An object will be successfully moved of no object is in that space. If an object is there, it's bound expression will be evaluated. Norally, it would be (hear "thud") or someting. Maybe not and just (). But doors will be (noise "nock nock") perhaps. Maybe not since people lagged will run into them and keep moving in that direction. That would be annoying. This might have been an issue with the first World implementation. Hmmm. Problem. Not allowing a person to move that direction would work since after a door was opened how would I allow the user to walk in? I like preventing users from continuing what they're doing as people walking in a wall indefinately is costly from an IPC perspective. Thu Jun 14 16:38:26 /etc/localtime 2001 Still trying to work out the details. I realized it would be nearly impossible syncing everyones map cache. (Which, by the way, I'm removing in favor of the OS's disk cache. I relied on it with the past versions of world, why not now? Guess I got a little gun-ho ther.) I'd have to have one dedicated spirit which was the only thing that kept track of map data. This, I suppose, is inevitable. I would also have to send all movmement 'requests' to it which would respond to everyone what just happened (probably as an ANSI string or more general update-this-cell-to-this-representation function). It 'seemed' to expensive sending out a request to move an object and only doing so when the response to actually came back to mutate the map. But isn't this how most internet related process work? People connecting to world assume this model: I send a char, a response, namley to mutate my screen, returns, or doesn't. But once again, this is server/client model I was trying to avoid otherwise World will be dependent on a server always running. I'm attempting to come up with a middle ground. People could connect and do some basic things but not those that would require 'spirit' control. So, first thing I'll do is work on a 'spirit' that sends new users complete maps and minute mutations periodically. Blah. So how to synchronize the spirit's 'cached' maps with the database? It would be nice if the movement-spirit MS could write it, then tell send the message to the person to load it. Question is will it stay synced with everyone after that? spirit-born shrewm-connects spirit->shrewm map and current-location shrewm->spirit up spirit->everyone mutate location and new location shrewm->spirit right shrewm->spirit right spirit->everyone mutate location and new location spirit->everyone mutate location and new location shrewm->spirit right emily-connects shrewm->spirit right spirit->everyone mutate location and new location spirit->emily map and current-location spirit->everyone mutate location and new location Going to redo the ipc mechanism to allow for multi-channels. For now, one will be used to send object/avatar movement requests to the movement ipc, which will also be the only entity mutating the map database. Tue Jul 3 18:50:12 /etc/localtime 2001 Archived: v3-6.4.tgz Started hax0ring the world on k9 (which was before this last June 14th save I think). So I'm going to continue with that one for now. I've archived v3-6.4.tgz my short-lived attempt at a new reality paradigm. What I've done is to keep avatars a completley separate component of the realityl, just like I've been doing. The difference is the way they attempt to move around and what cells' bindings are evaluated. An attempt to move in a direction results in calculating the new location and jumping there while setting the last position to where the avatar started. If the location contains a cell smaller than 256 (normal character) then that is considered 'air' or empty space and the avatars position is syncronized with everyone else via the ipc. If the location contained a solid cell/object/ atom (can't decide what to call it now) then the avatar is told to move back (walk 0) which results in the current position being where it started BUT the last position where it wanted to go. This desired locations cell's binding is then evaluated. This is opposite what I've done up until now which was to always successfully move to a position but depend on the result of the positions cell's binding to create unmoveable locations or actions. But this was difficult as syncing and handling bindings that forced another walk were difficult to combine. As an example, I've created a 'slide' that when walked on actually moves the avatar around a path (each motion sleeps for 100ms). Walls will be bound to () and doors bound to (if (own 'key) (walk 0) (hear "you need a key")) or something. Stairs will be to (jump DesiredLocation+Y). But now stairs means I'll actually have to get 3D! Woo hoo! Currently In the middle of implementing map-cell-top stuff. I might have to re-write the map code to streamline this new volume based map tendancy over the plane based. Wed Jul 4 20:11:51 /etc/localtime 2001 Successfully implemented a newer reality engine. When walking around, gravity has an affect on your position so your constaly 'walked' down until you hit something solid or the bottom of the plane. I need to do chem so I won't say much more. Oh well. See notes for specific points I came up with. Fri Jul 6 08:58:43 /etc/localtime 2001 Thought I had a big world bug due to random crashes especially walking betweeen planes. I narrowed it down to movement being called via the IPC which involved the ipc handler thread. When the movement function was called directly, not via the threaded ipc handler, it wouldn't crash. I had a feeling it might be the interpreter but wanted to make sure so performed random changes to the map functions. Whenever I simplified the map routines it wouldn't crash. As it turns out I wasn't allocating threads enough stack space (only #x200 bytes?). I found this somewhat on accident when grep'ing for new_stack in the thread code. Weird since the normal stack I gave #x8000 bytes. Simplifying the map routines reduced the strain on the thread's stack and so It wouldn't crash as much. This hopefully will solve the random crash attempt I noticed when uploading this new reality engine to k9. We'll see as I'm going to put i back now. Oh, I spent about 6 hours on this bug. Mon Jul 9 12:14:24 PDT 2001 Streamlined terminal sensing. It asks now if it can't figure it via the ioctl call. It also remembers current settings when asking so you can just hit return twice to accept current terminal dimensions. Would like to add support for signals so that the SIGWINCH will automatically set terminal size. I also cleaned up line input. It honors ^L which will just redraw the buffer at the bottom of the text window. On my terminal, backspace is supported all the back to the beginning of the input prompt. Nice. Still might have garbage find itself into the main text area when othe rtext scrolls by or after entering a large length of text. Solution would be to make the input area a window (must be 2 lines) but then it would get complicated remembering how long it was to maximize text window usage or just waste 2 lines for a mostly unused text window. Hmm. Of course I could just go the route of IRC and have a 'scrolling' input line. Hmm. Sun Sep 30 09:57:04 /etc/localtime 2001 Redoing the interface. Now hitting tab toggles between 'talk mode' and 'map mode'. While in talk mode, hitting ^G allows you to enter an expression to be evaluated. Woot! It was confusing for us old timers so I put back t for singe talk. I also have the cursor remain on so you can see whether your talking or mapping around.