# # model.icn - classes for static stuff # openings, doors, wall, box, room # which creates the 3D architecture # # plane = 1 x plane has all x coords equal and thus is parallel to yz plane # and perpendicular to x axis # plane = 2 y plane has all y coords equal and thus is parallel to xz plane # and perpendicular to y axis - typically floor and ceiling # plane = 3 z plane has all z coords equal and thus is parallel to xy plane # and perpendicular to z axis link printf # -------------------------------- # # class Opening is any cut-out in an instance of class Wall # special case: class Door below which renders a moveable door # in the opening. # class Opening ( x, y, z, width, height, plane, rooms, collide, is_rendered, delt ) #(x,y,z, width, height, thickness, rooms, textures, # rotator, openness, hinge_left, direction, delt, is_rendered, # plane, open_angle) method add_room(r) ## Opening put(rooms, r) end method other(room) ## Opening local r every r := !rooms do if r ~=== room then return r write("other room failed") end method allows(px,pz) ## Opening # write ( "Opening ", image(self) ) # write ( " allows plane, x, z, px pz",plane," ",x," ",z," ",px," ",pz," ") if ( ( plane = 3 ) & # z plane ( x+0.3 < px < x + width-0.3 ) & ( abs( z - pz ) < collide+ 0.10) ) then { return } if ( ( plane = 1 ) & # x plane ( z+0.3 < pz < z + width-0.3 ) & ( abs( x - px ) < collide + 0.10) ) then return fail end method render() ## Opening return end method print_opening() ## Opening local rm printf(" opening x,y,z,w,h,t %6.2r %6.2r %6.2r %6.2r %6.2r \n", x, y, z, width, height ) # printf(" openness, direction delt %6.2r %6.2r %6.2r \n", # openness, direction, delt ) write(" plane ", plane ) write(" # rooms ",*rooms) every rm := !rooms do write(" room ", image(rm) ) write(" " ) end # method print_opening() initially( x_in , y_in , z_in , collide_in, wd_in) # ,width,height,thickness) ## Opening # be sure x,y,z,w,h,t are floats x := x_in y := y_in z := z_in width := wd_in / width := 1.0 # default = 1 meter / height := 2.0 # default = 2 meters collide := (\collide_in | 0.8) # maybe should reduce to 0.8 or less rooms := [] plane := &null # set to 1 for xplane 3 for zplane delt := 0 end # class Opening # # class Door represents a closable connection between rooms # this will be sub-class of class Opening which itself has no door, but # provides the opening # class Door:Opening( x, y, z, thickness, rotator, openness, hinge_left, direction, delt, open_angle , texture, is_rendered) # (x,y,z, width, height, thickness, rooms, textures, # rotator, openness, hinge_left, direction, delt, is_rendered, # plane, open_angle) method add_room(r) ## Door put(rooms, r) end method other(room) ## Door local r every r := !rooms do if r ~=== room then return r write("other room failed") end # **************** needs work here method allows(px,pz) ## Door if openness < 0.67 then fail return self$Opening.allows(px,pz) end method dist1( px, py, pz ) ## Door return ( ( ( abs( px - x ) ^ 2.0 ) + ( abs ( pz - z ) ^ 2.0 ) ) ^ 0.50 ) end method distance(px,py,pz) ## Door # xplane zplane issues ??? # write ( " door distance px x ",px," ", x ) # write ( " pz z ",pz," ", z ) # write ( " dist 1 ", dist1( px, py, pz ) ) # write ( " dist 2 ", dist1( px, py, pz ) ) if plane = 3 then { # zplane return min ( dist1( px , py, pz ), dist1( px + width, py, pz ) ) } else { # plane = 1 x plane return min ( dist1( px , py, pz ), dist1( px , py, pz + width ) ) } end # method distance method done_opening() delt := 0 end method start_opening() direction *:= -1 delt := 0.03 end method delta() if (direction=1 & openness < 1) | (direction=-1 & openness > 0) then { set_openness(openness + direction * delt) return } end method set_openness(o) openness := o openness <:= 0 openness >:= 1 if \rotator then { rotator.angle := 90.0 * openness if /hinge_left then rotator.angle *:= -1.0 } end method render() ## Door if \is_rendered then return is_rendered := 1 if (type(self))[1+:4] ~== "Door" then return set_open_angle() if world.current_texture ~=== texture then { world.current_texture := texture } if WAttrib("texture="||\texture) then { WAttrib("texcoord= 0,0, 0,1, 1,1, 1,0") } else { WAttrib("texmode=off", "fg=very light yellow") } if plane = 3 then { # zplane - code renders ok render_z() } else { if plane = 1 then render_x() else write(" door rendering fails " ) } end # method render() method render_z() ## Door # write(" entering render_z ") PushMatrix() Translate(x,y,z) if /hinge_left then Translate(width,0,0) if \openness then { if \hinge_left then rotator := Rotate(-90.0 * openness, 0,1, 0) else rotator := Rotate(-90.0 * openness, 0, 1, 0) } if \hinge_left then { PushMatrix() Translate( -width/2.0, -height/2.0, -thickness/2.0) Scale(width,height,thickness) Translate( width , height/2.0 , thickness/2.0 ) DrawCube(0,0,0,1) PopMatrix() WAttrib("texmode=off") # this is not very general ######## Fg("brown") DrawSphere((width*0.92), height/2.0, 0.08, 0.04) DrawSphere((width*0.92), height/2.0, -0.08-thickness, 0.04) WAttrib("texmode=on") } else { # normal door = hinge right PushMatrix() Translate( -width/2.0, height/2.0, -thickness/2.0) Scale(width,height,thickness) DrawCube(0,0,0,1) PopMatrix() WAttrib("texmode=off") # this is not very general ######## Fg("brown") DrawSphere((-width*0.92), height/2.0, 0.08, 0.04) DrawSphere((-width*0.92), height/2.0, -0.08-thickness, 0.04) WAttrib("texmode=on") } PopMatrix() end # method render_z() method render_x() ## Door # write(" enter render_x " ) PushMatrix() Translate(x,y,z) # if /hinge_left then Translate(0.0, 0.0, width ) if \openness then { if \hinge_left then rotator := Rotate(-90.0 * openness, 0,1, 0) else rotator := Rotate( 90.0 * openness, 0, 1, 0) } if \hinge_left then { PushMatrix() Translate( -thickness/2.0, -height/2.0, -width/2.0) Scale(thickness,height,width) Translate( thickness/2.0 , height/2.0 , width ) DrawCube(0,0,0,1) PopMatrix() WAttrib("texmode=off") # this is not very general ######## Fg("brown") DrawSphere( 0.08 , height/2.0, (width*0.92), 0.04) DrawSphere(-0.08-thickness, height/2.0, (width*0.92), 0.04) WAttrib("texmode=on") } else { PushMatrix() Translate( -thickness/2.0, height/2.0, -width/2.0) Scale(thickness,height,width) #Translate( thickness/2.0 , height/2.0 , width ) Translate( 0 , 0 , width ) DrawCube(0,0,0,1) PopMatrix() WAttrib("texmode=off") # this is not very general ######## Fg("brown") DrawSphere( 0.08 , height/2.0, (width*0.92), 0.04) DrawSphere(-0.08-thickness, height/2.0, (width*0.92), 0.04) WAttrib("texmode=on") } PopMatrix() end # method render_x() method print_door() ## Door local rm printf(" door x,y,z,w,h,t %6.2r %6.2r %6.2r %6.2r %6.2r %6.2r \n", x, y, z, width, height, thickness ) printf(" openness, direction delt %6.2r %6.2r %6.2r \n", openness, direction, delt ) write(" plane ", plane ) write(" # rooms ",*rooms) every rm := !rooms do write(" room ", image(rm) ) write(" " ) end # method print_door() method set_open_angle() # Door if plane = 1 then { if /hinge_left then open_angle := 90.00 else open_angle := -90.00 } if plane = 3 then { if /hinge_left then open_angle := -90.00 else open_angle := 90.00 } end # method set_open_angle() # class Door:Opening( x, y, z, thickness, rotator, openness, hinge_left, direction, # delt, open_angle , texture, is_rendered) initially(x1, y1, z1, collide_in, tex, ht) # ,width,height,thickness) ## Door self$Opening.initially( ) # (x, y, z) # be sure x,y,z,w,h,t are floats self.x := x1 self.y := y1 self.z := z1 # / x := 0.0 # / y := 0.0 # / z := 0.0 / width := 1.0 # default = 1 meter height := ht / height := 2.6 # default = 2.6 meters / thickness := 0.03 # something over an inch thick texture := tex # default texture for this room openness := 0.00 direction := 1.00 delt := 0.03 hinge_left := &null open_angle := 0.00 is_rendered := &null plane := 3 end # class Door # # class Wall is a textured polygon # class Wall(texture, coords, minx, maxx, miny, maxy, minz, maxz, xdelta, ydelta, zdelta, plane, tex_fact) method calc_boundbox() ## Box local w, L, i maxx := minx := coords[1] maxy := miny := coords[2] maxz := minz := coords[3] L := coords every i := 4 to *L by 3 do { minx >:= L[i] maxx <:= L[i] miny >:= L[i+1] maxy <:= L[i+1] minz >:= L[i+2] maxz <:= L[i+2] } end method dist( p1, p2, p3, p4, p5, p6 ) ## Wall return ( ( ( abs( p4 - p1 ) ^ 2.0 ) + ( abs( p5 - p2 ) ^ 2.0 ) + ( abs( p6 - p3 ) ^ 2.0 ) ) ^ 0.50 ) end # method dist() method render() ## Wall local txcoords, i, c, mult_1, mult_2, tmp if world.current_texture ~=== texture then world.current_texture := texture # /tex_fact := [ 0.2, 0.2 ] # this should be a field in a texture object tex_fact := "off" # big debug printout # printf( "\n\n BEGIN WALL:::: \n" ) # self.printwall() # c := coords # printf( "\nWall: max x %8.2r, max y %8.2r, max z %8.2r \n", xdelta, ydelta, zdelta ) # self.printwall() if plane = 3 then { # z plane if tex_fact === "off" then { mult_1 := 1 mult_2 := 1 }else { mult_1 := xdelta / tex_fact[1] mult_2 := ydelta / tex_fact[2] } txcoords := [0.0, 0.0, 0.0, mult_2, mult_1, mult_2, mult_1, 0.0] # best # printf( " z_plane mult_1 mult_2 : %6.2r %6.2r \n",mult_1,mult_2 ) } else { if plane = 2 then { # y plane if tex_fact === "off" then { mult_1 := 1 mult_2 := 1 }else { mult_1 := xdelta / tex_fact[1] mult_2 := zdelta / tex_fact[2] } txcoords := [0.0, 0.0, 0.0, mult_2, mult_1, mult_2, mult_1, 0.0] # best # printf( " y_plane mult_1 mult_2 : %6.2r %6.2r \n",mult_1,mult_2 ) } else { if plane = 1 then { # x plane if tex_fact === "off" then { mult_1 := 1 mult_2 := 1 }else { mult_1 := zdelta / tex_fact[2] mult_2 := ydelta / tex_fact[1] } txcoords := [0.0, 0.0, 0.0, mult_2, mult_1, mult_2, mult_1, 0.0] # best # printf( " x_plane mult_1 mult_2 : %6.2r %6.2r \n",mult_1,mult_2 ) } else { write( " Render fails on Wall ") self.printwall() } } } # printf(" tx : %6.2r %6.2r %6.2r %6.2r \n", # txcoords[3],txcoords[4], txcoords[5],txcoords[6] ) # printf(" tx : %6.2r %6.2r %6.2r %6.2r \n", # txcoords[1],txcoords[2], txcoords[7],txcoords[8] ) # write (" texture : ", texture ) # # write( " end Wall:::" ) tmp := txcoords[1] || "," || txcoords[2] || "," || txcoords[3] || "," || txcoords[4] || "," || txcoords[5] || "," || txcoords[6] || "," || txcoords[7] || "," || txcoords[8] if WAttrib("texture="||\texture) then WAttrib("texcoord=" || tmp ) else write("no texture in wall, wanted ", image(\texture)) (FillPolygon ! coords) | write("FillPolygon fails") end # method render() method settexture(newtext) ## Wall # write( " resetting texture to ",newtext) texture := newtext # render() end method printwall() ## Wall local c c := coords printf(" Wall: %6.2r %6.2r %6.2r %6.2r %6.2r %6.2r \n", c[4],c[5],c[6],c[7],c[8],c[9] ) printf(" Wall: %6.2r %6.2r %6.2r %6.2r %6.2r %6.2r \n", c[1],c[2],c[3],c[10],c[11],c[12] ) write(" ------------------- ") end method set_plane() ## Wall local c plane := &null if /coords | (*coords=0) then fail c := coords if *c < 12 then stop("fatal: short wall needs 12 coordinates, had "|| *c) xdelta := max( abs( c[4]-c[1] ), abs(c[7]-c[4]), abs(c[10]-c[7]), abs(c[10] - c[1] ) ) ydelta := max( abs( c[5]-c[2] ), abs(c[8]-c[5]), abs(c[11]-c[8]), abs(c[11] - c[2] ) ) zdelta := max( abs( c[6]-c[3] ), abs(c[9]-c[6]), abs(c[12]-c[9]), abs(c[12] - c[3] ) ) if -0.0001 < zdelta < 0.05 then plane := 3 else if -0.0001 < ydelta < 0.05 then plane := 2 else if -0.0001 < xdelta < 0.05 then plane := 1 else { write( "Wall does not have a plane! " ) printwall() } end # method set_plane() method sort_coords() local L, T, d, c, i, j, k # sort is disabled return T := table() c := copy(coords) every i := 1 to *c by 3 do { d := dist( c[i], c[i+1], c[i+2], 0.0, 0.0, 0.0 ) T[i] := d } L := sort(T, 4) # sort by value, return list of alternating key,value k := 1 every i := (1 | 3 | 7 | 5) do { j := L[i] coords[k ] := c[j ] coords[k+1] := c[j+1] coords[k+2] := c[j+2] k +:= 3 } end # method sort_coords() initially(t, c[]) ## Wall texture := t coords := c sort_coords() set_plane() end # class Wall # # this class should not merge with class Room; # it has a separate existence because of obstacles and such # class Box( walls, minx, miny, maxy, maxx, minz, maxz, collide) # dtexture, collide ) method mkwall( x[] ) ## Box local w, t if type(x[1]) == "string" then t := pop(x) else t := world.d_wall_tex w := Wall ! push(x, t) put(walls, w) end method render() ## Box every (!walls).render() end # why did Box.disallows get removed? Someone not understand obstacles? method disallows(x,z) ## Box if /minx then calc_boundbox() if minx-collide <= x <= maxx+collide & minz-collide <= z <= maxz+collide then { return } end method calc_boundbox() ## Box local w, L, i maxx := minx := walls[1].coords[1] maxy := miny := walls[1].coords[2] maxz := minz := walls[1].coords[3] every w := !walls do { L := w.coords every i := 1 to *L by 3 do { # write(" L[i,i+1,i+2] ",L[i]," ",L[i+1]," ",L[i+2] ) minx >:= L[i] maxx <:= L[i] miny >:= L[i+1] maxy <:= L[i+1] minz >:= L[i+2] maxz <:= L[i+2] } } end initially() ## Box walls := [] # dtexture := world.find_texture("walltest.gif") # default texture for this room collide := world.collide # distance to maintain camera from walls to keep # textures unpixelated end # class Box # # class Room would denote a block with bounding walls. # Inside it are obstacles (affect movement) and decorations. # Exits may include doors and openings, both connecting to # other "Rooms". Cooridoors are rooms with openings. # # Room forms a natural unit of visibility, especially # when doors are closed. This may reduce the amount # of the world that needs to be rendered and the number # of textures that have to be loaded. # class Room : Box(floor, ceiling, obstacles, # things that should stop movement decorations, # things to just look at exits, # x-y ways to leave room name, # world, nearest_door, # avatar picks this one to open debug # switch for detailed debug info ) # a room disallows a move if: (a) outside or (b) something in the way method disallows(x,z) ## Room # return disallows, fail allows local msg, o, e # write("checking if ", name, " disallows ",x,",",z) if /minx then calc_boundbox() # write( " minx-maxx minz-maxz x z ",minx,"-",maxx," ",minz,"-", maxz," ",x," ",z ) if minx+collide <= x <= maxx-collide & minz+collide <= z <= maxz-collide then { every o := !obstacles do { if o.disallows(x,z) then { return ############# ????? ww. } } fail } else { every e := !exits do { if e.allows(x,z) then { if minx <= x <= maxx & minz <= z <= maxz then { #write("allow but don't change, still in ", # world.curr_room.name) } else { # change rooms and notify other users if \ (world.connection.connID) then { msg := "\\say leaves " || world.curr_room.name || " and enters " || e.other(self).name || " " # write( " debug move msg:" || msg ) write( world.connection.connID, msg ) } world.curr_room := e.other(self) } fail } } return } return end # method disallows ## Room method render() ## Room WAttrib("texmode=on") # write(" PRINTING OPENINGS ") # every (!exits).print_opening() every (!exits).render() # write(" floor.printwall() : " ) # floor.printwall() floor.render() ceiling.render() every (!walls).render() every (!obstacles).render() every (!decorations).render() end # figure out what wall this opening is in, and tear a hole in it, # for example, find the wall the opening is in, # remove that wall, and replace it with three sub-pieces of wall method add_opening(d) ## Room local c, i ,w, w2, w3, jj # list walls can be modified inside the loop, but doing so # gives "interesting" generator behavior, so if you do so, # it is wise to break or return out of the loop every jj := 1 to *walls do { w := walls[jj] # write("checking wall ",jj,"/",*walls," on plane ", w.plane, # " in room ", name, " for ", image(d)[8:0]) # w.sort_coords() c := w.coords if \debug then w.printwall() if (w.plane = 1) & (d.plane=1) then { # x plane if /(w.minx) then w.calc_boundbox() if ( abs(d.x - c[1]) < 0.08 & w.minz <= d.z <= w.maxz & w.miny <= d.y <= w.maxy ) then { # opening is in an xplane wall if d.z+d.width > w.maxz then { write("door/opening might be too wide for ", name) next } if d.y+d.height > w.maxy then { write("door/opening might be too high for ", name) next } # write("opening is on an xplane wall?") # remove this wall while walls[1] ~=== w do put(walls,pop(walls)) pop(walls) # replace it with three segments: # w = above, w2 = left, and w3 = right of door w2 := Wall ! ([w.texture] ||| w.coords) w3 := Wall ! ([w.texture] ||| w.coords) # write( "room add_door x,y,w,h ",d.x," ",d.y," ",d.width, # " ",d.height) every i := 1 to *w.coords by 3 do { w.coords[ i+1] <:= d.y + d.height w2.coords[i+1] >:= d.y + d.height w3.coords[i+1] >:= d.y + d.height w2.coords[i+2] >:= d.z w3.coords[i+2] <:= d.z + d.width } w.sort_coords() w.set_plane() w2.sort_coords() w2.set_plane() w3.sort_coords() w3.set_plane() put(walls, w, w2, w3) d.plane := 1 put(exits, d) d.add_room(self) # write( "room add_opening plane ", d.plane) # write( " adding wall w ") # w.printwall() # write( " adding wall w2 ") # w2.printwall() # write( " adding wall w3 ") # w3.printwall() return } } else { if (w.plane = 3) & (d.plane=3) then { if /(w.minx) then w.calc_boundbox() #write("checking a zplane wall ", image(d.z), " vs. ", c[3]) if (abs(d.z - c[3]) < 0.08 & w.minx <= d.x & d.x+d.width <= w.maxx & w.miny <= d.y & d.y+d.height <= w.maxy ) then { # door is in a zplane wall #write("found door on zplane wall in room ", name) # remove this wall while walls[1] ~=== w do put(walls,pop(walls)) pop(walls) # replace it with three segments: # w = above, w2 = left, and w3 = right of door w2 := Wall ! ([w.texture] ||| w.coords) w3 := Wall ! ([w.texture] ||| w.coords) # write( "room add_door x,y,w,h ",d.x," ",d.y," ",d.width," ",d.height) every i := 1 to *w.coords by 3 do { w.coords[ i+1] <:= d.y + d.height w2.coords[i+1] >:= d.y + d.height w3.coords[i+1] >:= d.y + d.height w2.coords[i] >:= d.x w3.coords[i] <:= d.x + d.width } w.sort_coords() w.set_plane() w2.sort_coords() w2.set_plane() w3.sort_coords() w3.set_plane() put(walls, w, w2, w3) put(exits, d) d.plane := 3 d.add_room(self) # write( "room add_door plane open_angle ", d.plane," ",d.open_angle) # write( " adding wall w ") # w.printwall() # write( " adding wall w2 ") # w2.printwall() # write( " adding wall w3 ") # w3.printwall() return } } } } write(&errout, "no wall found for ", image(d), " from room ", name, " to ", (d.other(self).name) | "?") if \debug then d.print_door() end # method add_opening ## Room # obj is cam or avatar method select_nearest_door( obj ) ## Room local i, idx, minval, tmp every i := 1 to *exits do { if type(exits[i])[1+:4] ~== "Door" then next tmp := exits[i].distance(obj.x, obj.y, obj.z) if /minval | (tmp < minval) then { idx := i minval := tmp } } nearest_door := exits[\idx] end # method select_nearest_door ## Room method add_obstacle(o) ## Room put(obstacles, o) end method add_decoration(d) ## Room put(decorations, d) end # really need multi textures - floor, wall, ceiling if we're going to have # defaults at this level... initially(nam,x,y,z,w,h,l,tex) ## Room self$Box.initially() # world := worl # dtexture := world.d_wall_tex nearest_door := &null name := nam floor := Wall(world.d_floor_tex, x, y , z, x, y , z+l, x+w, y , z+l, x+w, y , z ) ceiling:= Wall(world.d_ceil_tex, x, y+h, z, x, y+h, z+l, x+w, y+h, z+l, x+w, y+h, z ) mkwall(x, y, z+l, x , y+h, z+l, x+w, y+h, z+l, x+w, y, z+l) # back wall (3'?) mkwall(x+w, y, z , x+w, y+h, z , x+w, y+h, z+l, x+w, y, z+l) # right wall mkwall(x, y, z , x , y+h, z , x , y+h, z+l, x , y, z+l) # left wall mkwall(x, y, z , x , y+h, z , x+w, y+h, z , x+w, y, z ) # front wall exits := [] obstacles := [] decorations := [] collide := world.collide debug := &null end # class Room procedure parsebox(s, f) local b, w #write("parsebox") b := Box() s ? { tab(many(' \t')) ="{" tab(many(' \t')) s := tab(0) } while not (s ? (tab(many(' \t')) & ="}" & *tab(0)=0)) do { s ? { tab(many(' \t')) if ="Wall" then { w := parsewall(tab(0), f) put(b.walls, w) } } s := readlin(f) } return b end procedure parselelems(L, s, f) local elem #write("parselelem ", image(s)) s ? { tab(many(' \t')) if ="Box" then { elem := parsebox(tab(0), f) put(L, elem) } else if ="Wall" then { elem := parsewall(tab(0), f) put(L, elem) } else if ="WhiteBoard" then { elem := parsewall(tab(0), f) # elem := WhiteBoard ! (push(elem.coords, elem.texture,self.dispatcher,self, self.opMode)) # put(L, elem) } else if ="Windowblinds" then { elem := parsewindowblinds(tab(0), f) # put(L, elem) } else if ="Chair" then { elem := parsechair(tab(0), f) # put(L, elem) } else if ="Table" then { elem := parsetable(tab(0), f) #write("parsetable called") # put(L, elem) } else if ="Pen" then { #write("parsepen is calling") elem := parsepen(tab(0), f) # put(L, elem) } else if ="Book" then { #write("parsebook is calling") elem := parsebook(tab(0), f) # put(L, elem) } else if ="Computer" then { elem := parsecomputer(tab(0), f) #write("parsecomputer is calling") # put(L, elem) } else if ="Printer" then { elem := parseprinter(tab(0), f) #write("parseprinter is calling") # put(L, elem) } else if ="Ramp" then { elem := parseramp(tab(0), f) #write("parseramp is calling") # put(L, elem) } else { while elem := trim(tab(find(","))) do { put(L, elem) ="," tab(many(' \t')) } elem := trim(tab(0)) if *elem>0 then put(L, elem) } } end procedure parselist(s,f) local L #write("parselist ", image(s)) L := [] while (*s=0) | (s[-1] ~== "]") do s ? { parselelems(L, s, f) s := readlin(f) } if s ~== "]" then parselelems(L, s[1:-1], f) return L end procedure parsewall(s,f) local w, field_s, t := table() s ? { tab(many(' \t')) ="{" tab(many(' \t')) s := tab(0) } while (*s=0) | (s[-1] ~== "}") do s ? { field_s := tab(find("}")|0) if *field_s>0 then { parsefield(t, field_s, f) } if (*s=0) | (s[-1] ~== "}") then s := readlin(f) } s ?:= (tab(many(' \t')) & tab(0)) if s ~== "}" then parsefield(t, s[1:-1], f) w := Wall ! ([t["texture"]] ||| (\ (t["coords"]) | [])) return w end procedure parsewindowblinds(s,f) local w, field_s, t := table() s ? { tab(many(' \t')) ="{" tab(many(' \t')) s := tab(0) } while (*s=0) | (s[-1] ~== "}") do s ? { field_s := tab(find("}")|0) if *field_s>0 then { parsefield(t, field_s, f) } if (*s=0) | (s[-1] ~== "}") then s := readlin(f) } s ?:= (tab(many(' \t')) & tab(0)) if s ~== "}" then parsefield(t, s[1:-1], f) # w := Windowblinds ( (\ (t["coords"]) | []), t["angle"], t["crod"], t["cblinds"],t["height"], t["width"]) # return w end procedure parsechair(s,f) local w, field_s, t := table() s ? { tab(many(' \t')) ="{" tab(many(' \t')) s := tab(0) } while (*s=0) | (s[-1] ~== "}") do s ? { field_s := tab(find("}")|0) if *field_s>0 then { parsefield(t, field_s, f) } if (*s=0) | (s[-1] ~== "}") then s := readlin(f) } s ?:= (tab(many(' \t')) & tab(0)) if s ~== "}" then parsefield(t, s[1:-1], f) # w := Chair ((\ (t["coords"]) | []), t["position"], t["color"], t["type"], t["movable"]) # if (\ t["action"]) then # w.action := t["action"] return w end procedure parsetable(s,f) local w, field_s, t := table() #write("parsetable entered") s ? { tab(many(' \t')) ="{" tab(many(' \t')) s := tab(0) } while (*s=0) | (s[-1] ~== "}") do s ? { field_s := tab(find("}")|0) if *field_s>0 then { parsefield(t, field_s, f) } if (*s=0) | (s[-1] ~== "}") then s := readlin(f) } s ?:= (tab(many(' \t')) & tab(0)) if s ~== "}" then parsefield(t, s[1:-1], f) # w := Table ( self.opMode, (\ (t["coords"]) | []), t["position"], t["color"],t["type"]) # if (\ t["action"]) then # w.action := t["action"] return w end procedure parsepen(s,f) local w, field_s, t := table() s ? { tab(many(' \t')) ="{" tab(many(' \t')) s := tab(0) } while (*s=0) | (s[-1] ~== "}") do s ? { field_s := tab(find("}")|0) if *field_s>0 then { parsefield(t, field_s, f) } if (*s=0) | (s[-1] ~== "}") then s := readlin(f) } s ?:= (tab(many(' \t')) & tab(0)) if s ~== "}" then parsefield(t, s[1:-1], f) # w := Pen (self.opMode, t["Id"], (\ (t["coords"]) | []) ,t["color"], t["Angle"]) return w end procedure parsebook(s,f) local w, field_s, t := table() s ? { tab(many(' \t')) ="{" tab(many(' \t')) s := tab(0) } while (*s=0) | (s[-1] ~== "}") do s ? { field_s := tab(find("}")|0) if *field_s>0 then { parsefield(t, field_s, f) } if (*s=0) | (s[-1] ~== "}") then s := readlin(f) } s ?:= (tab(many(' \t')) & tab(0)) if s ~== "}" then parsefield(t, s[1:-1], f) # w := Book (self.opMode, (\ (t["coords"]) | []), t["color"], t["Angle"]) return w end procedure parseramp(s,f) local w, field_s, t := table() s ? { tab(many(' \t')) ="{" tab(many(' \t')) s := tab(0) } while (*s=0) | (s[-1] ~== "}") do s ? { field_s := tab(find("}")|0) if *field_s>0 then { parsefield(t, field_s, f) } if (*s=0) | (s[-1] ~== "}") then s := readlin(f) } s ?:= (tab(many(' \t')) & tab(0)) if s ~== "}" then parsefield(t, s[1:-1], f) # w:= Ramp ( (\ (t["coords"]) | []), t["color"], t["type"], t["width"], t["height"], t["length"] ) return w end procedure parsecomputer(s,f) local w, field_s, t := table() s ? { tab(many(' \t')) ="{" tab(many(' \t')) s := tab(0) } while (*s=0) | (s[-1] ~== "}") do s ? { field_s := tab(find("}")|0) if *field_s>0 then { parsefield(t, field_s, f) } if (*s=0) | (s[-1] ~== "}") then s := readlin(f) } s ?:= (tab(many(' \t')) & tab(0)) if s ~== "}" then parsefield(t, s[1:-1], f) # w := Computer ( (\ (t["coords_mntr"]) | []),(\ (t["coords_cpu"]) | []),(\ (t["coords_kb"]) | []), t["color"], t["angle"]) return w end procedure parseprinter(s,f) local w, field_s, t := table() s ? { tab(many(' \t')) ="{" tab(many(' \t')) s := tab(0) } while (*s=0) | (s[-1] ~== "}") do s ? { field_s := tab(find("}")|0) if *field_s>0 then { parsefield(t, field_s, f) } if (*s=0) | (s[-1] ~== "}") then s := readlin(f) } s ?:= (tab(many(' \t')) & tab(0)) if s ~== "}" then parsefield(t, s[1:-1], f) # w := Printer ( (\ (t["coords"]) | []), t["color"], t["angle"]) return w end procedure parsefield(x,s,f) local field, val s ? { tab(many(' \t')) (field := tab(upto(' \t'))) | { write("fieldname expected: ", image(tab(0))) runerr(500, "model error") } tab(many(' \t')) val := parseval(tab(0),f) if field=="texture" then val := world.find_texture(val) if (field == "action") then { /(x["actors"]) := [] put(x["actors"], 1) } x [field] := val } end procedure parseval(s,f) local val s ? { tab(many(' \t')) if val := numeric(tab(many(&digits++"."))) then return val else if ="Wall" then return parsewall(tab(0), f) else if ="[" then return parselist(tab(0), f) else return trim(tab(0)) } end procedure parseplace(s,f) local t, line t := table() while line := readlin(f) do line ? { tab(many(' \t')) if ="}" then break if &pos = *&subject+1 then next parsefield(t, tab(0), f) } return t end procedure parseroom(s,f) local t, r t := parseplace(s,f) r := Room(t["name"], t["x"], t["y"], t["z"], t["w"], t["h"], t["l"], t["texture"]) every r.add_obstacle(!\ (t["obstacles"])) every r.add_decoration(!\ (t["decorations"])) return r end procedure readlin(f) local line if line := read(f) then { line[find("#", line):0] := "" return line } end procedure parsedoor(s,f) local t, d, r t := parseplace(s,f) d := Door(t["x"], t["y"], t["z"], t["collide_in"], t["texure"], t["h"]) d.plane := \ (t["plane"]) every r := !t["rooms"] do { world.RoomsTable[r].add_opening(d) } return d end procedure parseopening(s,f) local t, d, r t := parseplace(s,f) d := Opening(t["x"], t["y"], t["z"], t["collide_in"], t["w"]) d.height := \ (t["height"]) d.plane := \ (t["plane"]) every r := !t["rooms"] do { world.RoomsTable[r].add_opening(d) } return d end