// world.cpp: core map management stuff #include "cube.h" extern char *entnames[]; // lookup from map entities above to strings sqr *world = NULL; int sfactor, ssize, cubicsize, mipsize; header hdr; void settag(int tag, int type) // set all cubes with "tag" to space, if tag is 0 then reset ALL tagged cubes according to type { int maxx = 0, maxy = 0, minx = ssize, miny = ssize; loop(x, ssize) loop(y, ssize) { sqr *s = S(x, y); if(s->tag) { if(tag) { if(tag==s->tag) s->type = SPACE; else continue; } else { s->type = type ? SOLID : SPACE; }; if(x>maxx) maxx = x; if(y>maxy) maxy = y; if(x=SMALLEST_FACTOR) return; int lighterr = getvar("lighterror")*3; sqr *w = wmip[level]; sqr *v = wmip[level+1]; int ws = ssize>>level; int vs = ssize>>(level+1); block s = b; if(s.x&1) { s.x--; s.xs++; }; if(s.y&1) { s.y--; s.ys++; }; s.xs = (s.xs+1)&~1; s.ys = (s.ys+1)&~1; for(int x = s.x; xtype]++; r->type = SEMISOLID; // cube contains both solid and space, treated specially in the renderer loopk(MAXTYPE) if(nums[k]==4) r->type = k; if(!SOLID(r)) { int floor = 127, ceil = -128, num = 0; loopi(4) if(!SOLID(o[i])) { num++; int fh = o[i]->floor; int ch = o[i]->ceil; if(r->type==SEMISOLID) { if(o[i]->type==FHF) fh -= o[i]->vdelta/4+2; // crap hack, needed for rendering large mips next to hfs if(o[i]->type==CHF) ch += o[i]->vdelta/4+2; // FIXME: needs to somehow take into account middle vertices on higher mips }; if(fhceil) ceil = ch; }; r->floor = floor; r->ceil = ceil; }; if(r->type==CORNER) goto mip; // special case: don't ever split even if textures etc are different r->defer = 1; if(SOLID(r)) { loopi(3) { if(o[i]->wtex!=o[3]->wtex) goto c; // on an all solid cube, only thing that needs to be equal for a perfect mip is the wall texture }; } else { loopi(3) { if(o[i]->type!=o[3]->type || o[i]->floor!=o[3]->floor || o[i]->ceil!=o[3]->ceil || o[i]->ftex!=o[3]->ftex || o[i]->ctex!=o[3]->ctex || abs(o[i+1]->r-o[0]->r)>lighterr // perfect mip even if light is not exactly equal || abs(o[i+1]->g-o[0]->g)>lighterr || abs(o[i+1]->b-o[0]->b)>lighterr || o[i]->utex!=o[3]->utex || o[i]->wtex!=o[3]->wtex) goto c; }; if(r->type==CHF || r->type==FHF) // can make a perfect mip out of a hf if slopes lie on one line { if(o[0]->vdelta-o[1]->vdelta != o[1]->vdelta-SWS(w,x+2,y,ws)->vdelta || o[0]->vdelta-o[2]->vdelta != o[2]->vdelta-SWS(w,x+2,y+2,ws)->vdelta || o[0]->vdelta-o[3]->vdelta != o[3]->vdelta-SWS(w,x,y+2,ws)->vdelta || o[3]->vdelta-o[2]->vdelta != o[2]->vdelta-SWS(w,x+2,y+1,ws)->vdelta || o[1]->vdelta-o[2]->vdelta != o[2]->vdelta-SWS(w,x+1,y+2,ws)->vdelta) goto c; }; }; { loopi(4) if(o[i]->defer) goto c; }; // if any of the constituents is not perfect, then this one isn't either mip: r->defer = 0; c:; }; s.x /= 2; s.y /= 2; s.xs /= 2; s.ys /= 2; remip(s, level+1); }; void remipmore(block &b, int level) { block bb = b; if(bb.x>1) bb.x--; if(bb.y>1) bb.y--; if(bb.xso, v); if(dist32) v1 = 32; if(!v1) e.attr1 = 16; if(!v2 && !v3 && !v4) e.attr2 = 255; break; case MAPMODEL: e.attr4 = e.attr3; e.attr3 = e.attr2; case MONSTER: case TELEDEST: e.attr2 = (uchar)e.attr1; case PLAYERSTART: e.attr1 = (int)player1->yaw; break; }; addmsg(1, 10, SV_EDITENT, ents.length(), type, e.x, e.y, e.z, e.attr1, e.attr2, e.attr3, e.attr4); ents.add(*((entity *)&e)); // unsafe! if(type==LIGHT) calclight(); return &ents.last(); }; void clearents(char *name) { int type = findtype(name); if(noteditmode() || multiplayer()) return; loopv(ents) { entity &e = ents[i]; if(e.type==type) e.type = NOTUSED; }; if(type==LIGHT) calclight(); }; COMMAND(clearents, ARG_1STR); void scalecomp(uchar &c, int intens) { int n = c*intens/100; if(n>255) n = 255; c = n; }; void scalelights(int f, int intens) { loopv(ents) { entity &e = ents[i]; if(e.type!=LIGHT) continue; e.attr1 = e.attr1*f/100; if(e.attr1<2) e.attr1 = 2; if(e.attr1>32) e.attr1 = 32; if(intens) { scalecomp(e.attr2, intens); scalecomp(e.attr3, intens); scalecomp(e.attr4, intens); }; }; calclight(); }; COMMAND(scalelights, ARG_2INT); int findentity(int type, int index) { for(int i = index; i>(i*2); }; }; void empty_world(int factor, bool force) // main empty world creation routine, if passed factor -1 will enlarge old world by 1 { if(!force && noteditmode()) return; cleardlights(); pruneundos(); sqr *oldworld = world; bool copy = false; if(oldworld && factor<0) { factor = sfactor+1; copy = true; }; if(factorLARGEST_FACTOR) factor = LARGEST_FACTOR; setupworld(factor); loop(x,ssize) loop(y,ssize) { sqr *s = S(x,y); s->r = s->g = s->b = 150; s->ftex = DEFAULT_FLOOR; s->ctex = DEFAULT_CEIL; s->wtex = s->utex = DEFAULT_WALL; s->type = SOLID; s->floor = 0; s->ceil = 16; s->vdelta = 0; s->defer = 0; }; strncpy(hdr.head, "CUBE", 4); hdr.version = MAPVERSION; hdr.headersize = sizeof(header); hdr.sfactor = sfactor; if(copy) { loop(x,ssize/2) loop(y,ssize/2) { *S(x+ssize/4, y+ssize/4) = *SWS(oldworld, x, y, ssize/2); }; loopv(ents) { ents[i].x += ssize/4; ents[i].y += ssize/4; }; } else { strn0cpy(hdr.maptitle, "Untitled Map by Unknown", 128); hdr.waterlevel = -100000; loopi(15) hdr.reserved[i] = 0; loopk(3) loopi(256) hdr.texlists[k][i] = i; ents.setsize(0); block b = { 8, 8, ssize-16, ssize-16 }; edittypexy(SPACE, b); }; calclight(); startmap("base/unnamed"); if(oldworld) { free(oldworld); toggleedit(); execute("fullbright 1"); }; }; void mapenlarge() { empty_world(-1, false); }; void newmap(int i) { empty_world(i, false); }; COMMAND(mapenlarge, ARG_NONE); COMMAND(newmap, ARG_1INT); COMMANDN(recalc, calclight, ARG_NONE); COMMAND(delent, ARG_NONE); COMMAND(entproperty, ARG_2INT);