# # cve.icn - classes to support collaborative virtual environments # # # class Door represents a closable connection between rooms # special case: class Opening when no door is present # class Door(x,y,z, width, height, thickness, rooms, textures, rotator, openness, hinge_left, direction, delt, is_rendered) method add_room(r) put(rooms, r) end method other(room) local r every r := !rooms do if r ~=== room then return r write("other room failed") end method allows(px,pz) if openness < 0.67 then fail # write("door allows checking ", # left(px,4), ",", left(pz,4), " openness ", image(openness)) # write("x ", x,"-",x+width, " z ", z,"-",z+thickness) if x+0.3 <= px <= x+width-0.3 & z-1.2 <= pz <= z+thickness+1.2 then { # write("door allows says OK") return } end 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() if \is_rendered then return is_rendered := 1 WAttrib("texmode=off") Fg("very light yellow") 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 { FillPolygon(0,0,0, width,0,0, width,height,0, 0,height,0) } else{ PushMatrix() Translate(-width/2,height/2,-thickness/2) Scale(width,height,thickness) DrawCube(0,0,0,1) PopMatrix() Fg("brown") DrawSphere(-(width*.92), height/2.0, 0.08, 0.08) DrawSphere(-(width*.92), height/2.0, -0.08-thickness, 0.08) } PopMatrix() end initially / x := 0 / y := 0 / z := 0 / width := 1.5 # default = 3' / height := 3.5 # default = 7' / thickness := 0.05 # something over an inch thick rooms := [] openness := 0 direction := -1 delt := 0 end global current_texture # # class Wall is a textured polygon # class Wall(texture, coords) method render() if current_texture ~=== texture then { WAttrib("texture="||texture, "texcoord=0,0,0,1,1,1,1,0") current_texture := texture } (FillPolygon ! coords) | write("FillPolygon fails") end initially(t, c[]) texture := t coords := c end # Coordinate system: # y=0 is ground level # -5 < x < 5; -6 < z < 0; 2' per unit class Box( walls, minx, maxx, minz, maxz, dtexture) # default texture for this room method mkwall(x[]) local W, t if type(x[1]) == "string" then t := pop(x) else t := dtexture W := Wall ! push(x, t) put(walls, W) end method render() every (!walls).render() end method disallows(x,z) if /minx then calc_boundbox() if minx-1.2 <= x <= maxx+1.2 & minz-1.2 <= z <= maxz+1.2 then { return } end method calc_boundbox() local w, L, i maxx := minx := walls[1].coords[1] maxz := minz := walls[1].coords[3] every w := !walls do { L := w.coords every i := 1 to *L by 3 do { minx >:= L[i] maxx <:= L[i] minz >:= L[i+2] maxz <:= L[i+2] } } end initially walls := [] /dtexture := "walltest.gif" end # # 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 ) # a room disallows a move if: (a) outside or (b) something in the way method disallows(x,z) local e, o # write("checking if ", name, " disallows ",x,",",z) if /minx then calc_boundbox() if minx+1.2 <= x <= maxx-1.2 & minz+1.2 <= z <= maxz-1.2 then { every o := !obstacles do if o.disallows(x,z) then return fail } every e := !exits do { if e.allows(x,z) then { if minx <= x <= maxx & minz <= z <= maxz then { # allow but don't change room yet } else { curr_room := e.other(self) Cmds.ClientCommand(net, "\\say I have moved to room " || curr_room.name ) write("curr_room changed to ", curr_room.name) } fail } } return end method render() local w, ex every ex := !exits do ex.render() WAttrib("texmode=on") floor.render() ceiling.render() every w := !walls do { w.render() } every (!obstacles).render() every (!decorations).render() # WAttrib("texmode=off", "fg=green") # DrawCylinder(0, 0, -3, 2, 1, 1) end method add_door(d) local w, w2, w3, c, i put(exits, d) d.add_room(self) # figure out what wall this door is in, and tear a hole in it, # for example, find the wall the please door is in, # remove that wall, and replace them with three every w := !walls do { c := w.coords if c[1]=c[4]=c[7]=c[10] then { if d.x = c[1] then write("door is in xplane wall ", image(w)) } else if c[3]=c[6]=c[9]=c[12] then { if abs(d.z - c[3]) < 0.08 then { # door is in a zplane 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) 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 w2.coords[i] >:= d.x w3.coords[i+1] >:= d.y+d.height w3.coords[i] <:= d.x + d.width } put(walls, w, w2, w3) return } } else { write("no plane; giving up"); fail } } end method add_obstacle(o) put(obstacles, o) end method add_decoration(d) put(decorations, d) end initially(nam,x,y,z,w,h,l,tex) self$Box.initially() dtexture := \tex name := nam exits := [] floor := Wall("floor.gif",x,y,z, x,y,z-l, x+w,y,z-l, x+w,y,z) ceiling:= Wall("walltest.gif",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+1.5,z-l, x+w,y+1.5,z-l, x+w,y,z-l) # back wall (3'?) mkwall(x+w,y,z-l, x+w,y+h,z-l, x+w,y+h,z, x+w,y,z) # 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 obstacles := [] decorations := [] end