diff options
Diffstat (limited to 'src/engine/world.cpp')
| -rw-r--r-- | src/engine/world.cpp | 1895 |
1 files changed, 947 insertions, 948 deletions
diff --git a/src/engine/world.cpp b/src/engine/world.cpp index 7f5baed..af998c3 100644 --- a/src/engine/world.cpp +++ b/src/engine/world.cpp @@ -12,261 +12,261 @@ VAR(entselradius, 0, 2, 10); static inline void mmboundbox(const entity &e, model *m, vec ¢er, vec &radius) { - m->boundbox(center, radius); - rotatebb(center, radius, e.attr1); + m->boundbox(center, radius); + rotatebb(center, radius, e.attr1); } static inline void mmcollisionbox(const entity &e, model *m, vec ¢er, vec &radius) { - m->collisionbox(center, radius); - rotatebb(center, radius, e.attr1); + m->collisionbox(center, radius); + rotatebb(center, radius, e.attr1); } bool getentboundingbox(const extentity &e, ivec &o, ivec &r) { - switch(e.type) - { - case ET_EMPTY: - return false; - case ET_MAPMODEL: - { - model *m = loadmapmodel(e.attr2); - if(m) - { - vec center, radius; - mmboundbox(e, m, center, radius); - center.add(e.o); - radius.max(entselradius); - o = ivec(vec(center).sub(radius)); - r = ivec(vec(center).add(radius).add(1)); - break; - } - } - [[fallthrough]]; - // invisible mapmodels use entselradius - default: - o = ivec(vec(e.o).sub(entselradius)); - r = ivec(vec(e.o).add(entselradius+1)); - break; - } - return true; + switch(e.type) + { + case ET_EMPTY: + return false; + case ET_MAPMODEL: + { + model *m = loadmapmodel(e.attr2); + if(m) + { + vec center, radius; + mmboundbox(e, m, center, radius); + center.add(e.o); + radius.max(entselradius); + o = ivec(vec(center).sub(radius)); + r = ivec(vec(center).add(radius).add(1)); + break; + } + } + [[fallthrough]]; + // invisible mapmodels use entselradius + default: + o = ivec(vec(e.o).sub(entselradius)); + r = ivec(vec(e.o).add(entselradius+1)); + break; + } + return true; } enum { - MODOE_ADD = 1<<0, - MODOE_UPDATEBB = 1<<1, - MODOE_LIGHTENT = 1<<2 + MODOE_ADD = 1<<0, + MODOE_UPDATEBB = 1<<1, + MODOE_LIGHTENT = 1<<2 }; void modifyoctaentity(int flags, int id, extentity &e, cube *c, const ivec &cor, int size, const ivec &bo, const ivec &br, int leafsize, vtxarray *lastva = NULL) { - loopoctabox(cor, size, bo, br) - { - ivec o(i, cor, size); - vtxarray *va = c[i].ext && c[i].ext->va ? c[i].ext->va : lastva; - if(c[i].children != NULL && size > leafsize) - modifyoctaentity(flags, id, e, c[i].children, o, size>>1, bo, br, leafsize, va); - else if(flags&MODOE_ADD) - { - if(!c[i].ext || !c[i].ext->ents) ext(c[i]).ents = new octaentities(o, size); - octaentities &oe = *c[i].ext->ents; - switch(e.type) - { - case ET_MAPMODEL: - if(loadmapmodel(e.attr2)) - { - if(va) - { - va->bbmin.x = -1; - if(oe.mapmodels.empty()) va->mapmodels.add(&oe); - } - oe.mapmodels.add(id); - oe.bbmin.min(bo).max(oe.o); - oe.bbmax.max(br).min(ivec(oe.o).add(oe.size)); - break; - } - // invisible mapmodel - [[fallthrough]]; - default: - oe.other.add(id); - break; - } - - } - else if(c[i].ext && c[i].ext->ents) - { - octaentities &oe = *c[i].ext->ents; - switch(e.type) - { - case ET_MAPMODEL: - if(loadmapmodel(e.attr2)) - { - oe.mapmodels.removeobj(id); - if(va) - { - va->bbmin.x = -1; - if(oe.mapmodels.empty()) va->mapmodels.removeobj(&oe); - } - oe.bbmin = oe.bbmax = oe.o; - oe.bbmin.add(oe.size); - loopvj(oe.mapmodels) - { - extentity &e = *entities::getents()[oe.mapmodels[j]]; - ivec eo, er; - if(getentboundingbox(e, eo, er)) - { - oe.bbmin.min(eo); - oe.bbmax.max(er); - } - } - oe.bbmin.max(oe.o); - oe.bbmax.min(ivec(oe.o).add(oe.size)); - break; - } - [[fallthrough]]; - // invisible mapmodel - default: - oe.other.removeobj(id); - break; - } - if(oe.mapmodels.empty() && oe.other.empty()) - freeoctaentities(c[i]); - } - if(c[i].ext && c[i].ext->ents) c[i].ext->ents->query = NULL; - if(va && va!=lastva) - { - if(lastva) - { - if(va->bbmin.x < 0) lastva->bbmin.x = -1; - } - else if(flags&MODOE_UPDATEBB) updatevabb(va); - } - } + loopoctabox(cor, size, bo, br) + { + ivec o(i, cor, size); + vtxarray *va = c[i].ext && c[i].ext->va ? c[i].ext->va : lastva; + if(c[i].children != NULL && size > leafsize) + modifyoctaentity(flags, id, e, c[i].children, o, size>>1, bo, br, leafsize, va); + else if(flags&MODOE_ADD) + { + if(!c[i].ext || !c[i].ext->ents) ext(c[i]).ents = new octaentities(o, size); + octaentities &oe = *c[i].ext->ents; + switch(e.type) + { + case ET_MAPMODEL: + if(loadmapmodel(e.attr2)) + { + if(va) + { + va->bbmin.x = -1; + if(oe.mapmodels.empty()) va->mapmodels.add(&oe); + } + oe.mapmodels.add(id); + oe.bbmin.min(bo).max(oe.o); + oe.bbmax.max(br).min(ivec(oe.o).add(oe.size)); + break; + } + // invisible mapmodel + [[fallthrough]]; + default: + oe.other.add(id); + break; + } + + } + else if(c[i].ext && c[i].ext->ents) + { + octaentities &oe = *c[i].ext->ents; + switch(e.type) + { + case ET_MAPMODEL: + if(loadmapmodel(e.attr2)) + { + oe.mapmodels.removeobj(id); + if(va) + { + va->bbmin.x = -1; + if(oe.mapmodels.empty()) va->mapmodels.removeobj(&oe); + } + oe.bbmin = oe.bbmax = oe.o; + oe.bbmin.add(oe.size); + loopvj(oe.mapmodels) + { + extentity &e = *entities::getents()[oe.mapmodels[j]]; + ivec eo, er; + if(getentboundingbox(e, eo, er)) + { + oe.bbmin.min(eo); + oe.bbmax.max(er); + } + } + oe.bbmin.max(oe.o); + oe.bbmax.min(ivec(oe.o).add(oe.size)); + break; + } + [[fallthrough]]; + // invisible mapmodel + default: + oe.other.removeobj(id); + break; + } + if(oe.mapmodels.empty() && oe.other.empty()) + freeoctaentities(c[i]); + } + if(c[i].ext && c[i].ext->ents) c[i].ext->ents->query = NULL; + if(va && va!=lastva) + { + if(lastva) + { + if(va->bbmin.x < 0) lastva->bbmin.x = -1; + } + else if(flags&MODOE_UPDATEBB) updatevabb(va); + } + } } vector<int> outsideents; static bool modifyoctaent(int flags, int id, extentity &e) { - if(flags&MODOE_ADD ? e.flags&EF_OCTA : !(e.flags&EF_OCTA)) return false; - - ivec o, r; - if(!getentboundingbox(e, o, r)) return false; - - if(!insideworld(e.o)) - { - int idx = outsideents.find(id); - if(flags&MODOE_ADD) - { - if(idx < 0) outsideents.add(id); - } - else if(idx >= 0) outsideents.removeunordered(idx); - } - else - { - int leafsize = octaentsize, limit = max(r.x - o.x, max(r.y - o.y, r.z - o.z)); - while(leafsize < limit) leafsize *= 2; - int diff = ~(leafsize-1) & ((o.x^r.x)|(o.y^r.y)|(o.z^r.z)); - if(diff && (limit > octaentsize/2 || diff < leafsize*2)) leafsize *= 2; - modifyoctaentity(flags, id, e, worldroot, ivec(0, 0, 0), worldsize>>1, o, r, leafsize); - } - e.flags ^= EF_OCTA; - if(e.type == ET_LIGHT) clearlightcache(id); - else if(e.type == ET_PARTICLES) clearparticleemitters(); - else if(flags&MODOE_LIGHTENT) lightent(e); - return true; + if(flags&MODOE_ADD ? e.flags&EF_OCTA : !(e.flags&EF_OCTA)) return false; + + ivec o, r; + if(!getentboundingbox(e, o, r)) return false; + + if(!insideworld(e.o)) + { + int idx = outsideents.find(id); + if(flags&MODOE_ADD) + { + if(idx < 0) outsideents.add(id); + } + else if(idx >= 0) outsideents.removeunordered(idx); + } + else + { + int leafsize = octaentsize, limit = max(r.x - o.x, max(r.y - o.y, r.z - o.z)); + while(leafsize < limit) leafsize *= 2; + int diff = ~(leafsize-1) & ((o.x^r.x)|(o.y^r.y)|(o.z^r.z)); + if(diff && (limit > octaentsize/2 || diff < leafsize*2)) leafsize *= 2; + modifyoctaentity(flags, id, e, worldroot, ivec(0, 0, 0), worldsize>>1, o, r, leafsize); + } + e.flags ^= EF_OCTA; + if(e.type == ET_LIGHT) clearlightcache(id); + else if(e.type == ET_PARTICLES) clearparticleemitters(); + else if(flags&MODOE_LIGHTENT) lightent(e); + return true; } static inline bool modifyoctaent(int flags, int id) { - vector<extentity *> &ents = entities::getents(); - return ents.inrange(id) && modifyoctaent(flags, id, *ents[id]); + vector<extentity *> &ents = entities::getents(); + return ents.inrange(id) && modifyoctaent(flags, id, *ents[id]); } -static inline void addentity(int id) { modifyoctaent(MODOE_ADD|MODOE_UPDATEBB|MODOE_LIGHTENT, id); } +static inline void addentity(int id) { modifyoctaent(MODOE_ADD|MODOE_UPDATEBB|MODOE_LIGHTENT, id); } static inline void removeentity(int id) { modifyoctaent(MODOE_UPDATEBB, id); } void freeoctaentities(cube &c) { - if(!c.ext) return; - if(entities::getents().length()) - { - while(c.ext->ents && !c.ext->ents->mapmodels.empty()) removeentity(c.ext->ents->mapmodels.pop()); - while(c.ext->ents && !c.ext->ents->other.empty()) removeentity(c.ext->ents->other.pop()); - } - if(c.ext->ents) - { - delete c.ext->ents; - c.ext->ents = NULL; - } + if(!c.ext) return; + if(entities::getents().length()) + { + while(c.ext->ents && !c.ext->ents->mapmodels.empty()) removeentity(c.ext->ents->mapmodels.pop()); + while(c.ext->ents && !c.ext->ents->other.empty()) removeentity(c.ext->ents->other.pop()); + } + if(c.ext->ents) + { + delete c.ext->ents; + c.ext->ents = NULL; + } } void entitiesinoctanodes() { - vector<extentity *> &ents = entities::getents(); - loopv(ents) modifyoctaent(MODOE_ADD, i, *ents[i]); + vector<extentity *> &ents = entities::getents(); + loopv(ents) modifyoctaent(MODOE_ADD, i, *ents[i]); } static inline void findents(octaentities &oe, int low, int high, bool notspawned, const vec &pos, const vec &invradius, vector<int> &found) { - vector<extentity *> &ents = entities::getents(); - loopv(oe.other) - { - int id = oe.other[i]; - extentity &e = *ents[id]; - if(e.type >= low && e.type <= high && (e.spawned() || notspawned) && vec(e.o).sub(pos).mul(invradius).squaredlen() <= 1) found.add(id); - } + vector<extentity *> &ents = entities::getents(); + loopv(oe.other) + { + int id = oe.other[i]; + extentity &e = *ents[id]; + if(e.type >= low && e.type <= high && (e.spawned() || notspawned) && vec(e.o).sub(pos).mul(invradius).squaredlen() <= 1) found.add(id); + } } static inline void findents(cube *c, const ivec &o, int size, const ivec &bo, const ivec &br, int low, int high, bool notspawned, const vec &pos, const vec &invradius, vector<int> &found) { - loopoctabox(o, size, bo, br) - { - if(c[i].ext && c[i].ext->ents) findents(*c[i].ext->ents, low, high, notspawned, pos, invradius, found); - if(c[i].children && size > octaentsize) - { - ivec co(i, o, size); - findents(c[i].children, co, size>>1, bo, br, low, high, notspawned, pos, invradius, found); - } - } + loopoctabox(o, size, bo, br) + { + if(c[i].ext && c[i].ext->ents) findents(*c[i].ext->ents, low, high, notspawned, pos, invradius, found); + if(c[i].children && size > octaentsize) + { + ivec co(i, o, size); + findents(c[i].children, co, size>>1, bo, br, low, high, notspawned, pos, invradius, found); + } + } } void findents(int low, int high, bool notspawned, const vec &pos, const vec &radius, vector<int> &found) { - vec invradius(1/radius.x, 1/radius.y, 1/radius.z); - ivec bo(vec(pos).sub(radius).sub(1)), - br(vec(pos).add(radius).add(1)); - int diff = (bo.x^br.x) | (bo.y^br.y) | (bo.z^br.z) | octaentsize, - scale = worldscale-1; - if(diff&~((1<<scale)-1) || uint(bo.x|bo.y|bo.z|br.x|br.y|br.z) >= uint(worldsize)) - { - findents(worldroot, ivec(0, 0, 0), 1<<scale, bo, br, low, high, notspawned, pos, invradius, found); - return; - } - cube *c = &worldroot[octastep(bo.x, bo.y, bo.z, scale)]; - if(c->ext && c->ext->ents) findents(*c->ext->ents, low, high, notspawned, pos, invradius, found); - scale--; - while(c->children && !(diff&(1<<scale))) - { - c = &c->children[octastep(bo.x, bo.y, bo.z, scale)]; - if(c->ext && c->ext->ents) findents(*c->ext->ents, low, high, notspawned, pos, invradius, found); - scale--; - } - if(c->children && 1<<scale >= octaentsize) findents(c->children, ivec(bo).mask(~((2<<scale)-1)), 1<<scale, bo, br, low, high, notspawned, pos, invradius, found); + vec invradius(1/radius.x, 1/radius.y, 1/radius.z); + ivec bo(vec(pos).sub(radius).sub(1)), + br(vec(pos).add(radius).add(1)); + int diff = (bo.x^br.x) | (bo.y^br.y) | (bo.z^br.z) | octaentsize, + scale = worldscale-1; + if(diff&~((1<<scale)-1) || uint(bo.x|bo.y|bo.z|br.x|br.y|br.z) >= uint(worldsize)) + { + findents(worldroot, ivec(0, 0, 0), 1<<scale, bo, br, low, high, notspawned, pos, invradius, found); + return; + } + cube *c = &worldroot[octastep(bo.x, bo.y, bo.z, scale)]; + if(c->ext && c->ext->ents) findents(*c->ext->ents, low, high, notspawned, pos, invradius, found); + scale--; + while(c->children && !(diff&(1<<scale))) + { + c = &c->children[octastep(bo.x, bo.y, bo.z, scale)]; + if(c->ext && c->ext->ents) findents(*c->ext->ents, low, high, notspawned, pos, invradius, found); + scale--; + } + if(c->children && 1<<scale >= octaentsize) findents(c->children, ivec(bo).mask(~((2<<scale)-1)), 1<<scale, bo, br, low, high, notspawned, pos, invradius, found); } char *entname(entity &e) { - static string fullentname; - copystring(fullentname, entities::entname(e.type)); - const char *einfo = entities::entnameinfo(e); - if(*einfo) - { - concatstring(fullentname, ": "); - concatstring(fullentname, einfo); - } - return fullentname; + static string fullentname; + copystring(fullentname, entities::entname(e.type)); + const char *einfo = entities::entnameinfo(e); + if(*einfo) + { + concatstring(fullentname, ": "); + concatstring(fullentname, einfo); + } + return fullentname; } extern selinfo sel; @@ -279,138 +279,138 @@ VARF(entediting, 0, 0, 1, { if(!entediting) { entcancel(); efocus = enthover = - bool noentedit() { - if(!editmode) { conoutf(CON_ERROR, "operation only allowed in edit mode"); return true; } - return !entediting; + if(!editmode) { conoutf(CON_ERROR, "operation only allowed in edit mode"); return true; } + return !entediting; } bool pointinsel(const selinfo &sel, const vec &o) { - return(o.x <= sel.o.x+sel.s.x*sel.grid - && o.x >= sel.o.x - && o.y <= sel.o.y+sel.s.y*sel.grid - && o.y >= sel.o.y - && o.z <= sel.o.z+sel.s.z*sel.grid - && o.z >= sel.o.z); + return(o.x <= sel.o.x+sel.s.x*sel.grid + && o.x >= sel.o.x + && o.y <= sel.o.y+sel.s.y*sel.grid + && o.y >= sel.o.y + && o.z <= sel.o.z+sel.s.z*sel.grid + && o.z >= sel.o.z); } vector<int> entgroup; bool haveselent() { - return entgroup.length() > 0; + return entgroup.length() > 0; } void entcancel() { - entgroup.shrink(0); + entgroup.shrink(0); } void entadd(int id) { - undonext = true; - entgroup.add(id); + undonext = true; + entgroup.add(id); } undoblock *newundoent() { - int numents = entgroup.length(); - if(numents <= 0) return NULL; - undoblock *u = (undoblock *)new uchar[sizeof(undoblock) + numents*sizeof(undoent)]; - u->numents = numents; - undoent *e = (undoent *)(u + 1); - loopv(entgroup) - { - e->i = entgroup[i]; - e->e = *entities::getents()[entgroup[i]]; - e++; - } - return u; + int numents = entgroup.length(); + if(numents <= 0) return NULL; + undoblock *u = (undoblock *)new uchar[sizeof(undoblock) + numents*sizeof(undoent)]; + u->numents = numents; + undoent *e = (undoent *)(u + 1); + loopv(entgroup) + { + e->i = entgroup[i]; + e->e = *entities::getents()[entgroup[i]]; + e++; + } + return u; } void makeundoent() { - if(!undonext) return; - undonext = false; - oldhover = enthover; - undoblock *u = newundoent(); - if(u) addundo(u); + if(!undonext) return; + undonext = false; + oldhover = enthover; + undoblock *u = newundoent(); + if(u) addundo(u); } void detachentity(extentity &e) { - if(!e.attached) return; - e.attached->attached = NULL; - e.attached = NULL; + if(!e.attached) return; + e.attached->attached = NULL; + e.attached = NULL; } VAR(attachradius, 1, 100, 1000); void attachentity(extentity &e) { - switch(e.type) - { - case ET_SPOTLIGHT: - break; - - default: - if(e.type<ET_GAMESPECIFIC || !entities::mayattach(e)) return; - break; - } - - detachentity(e); - - vector<extentity *> &ents = entities::getents(); - int closest = -1; - float closedist = 1e10f; - loopv(ents) - { - extentity *a = ents[i]; - if(a->attached) continue; - switch(e.type) - { - case ET_SPOTLIGHT: - if(a->type!=ET_LIGHT) continue; - break; - - default: - if(e.type<ET_GAMESPECIFIC || !entities::attachent(e, *a)) continue; - break; - } - float dist = e.o.dist(a->o); - if(dist < closedist) - { - closest = i; - closedist = dist; - } - } - if(closedist>attachradius) return; - e.attached = ents[closest]; - ents[closest]->attached = &e; + switch(e.type) + { + case ET_SPOTLIGHT: + break; + + default: + if(e.type<ET_GAMESPECIFIC || !entities::mayattach(e)) return; + break; + } + + detachentity(e); + + vector<extentity *> &ents = entities::getents(); + int closest = -1; + float closedist = 1e10f; + loopv(ents) + { + extentity *a = ents[i]; + if(a->attached) continue; + switch(e.type) + { + case ET_SPOTLIGHT: + if(a->type!=ET_LIGHT) continue; + break; + + default: + if(e.type<ET_GAMESPECIFIC || !entities::attachent(e, *a)) continue; + break; + } + float dist = e.o.dist(a->o); + if(dist < closedist) + { + closest = i; + closedist = dist; + } + } + if(closedist>attachradius) return; + e.attached = ents[closest]; + ents[closest]->attached = &e; } void attachentities() { - vector<extentity *> &ents = entities::getents(); - loopv(ents) attachentity(*ents[i]); + vector<extentity *> &ents = entities::getents(); + loopv(ents) attachentity(*ents[i]); } // convenience macros implicitly define: -// e entity, currently edited ent -// n int, index to currently edited ent -#define addimplicit(f) { if(entgroup.empty() && enthover>=0) { entadd(enthover); undonext = (enthover != oldhover); f; entgroup.drop(); } else f; } +// e entity, currently edited ent +// n int, index to currently edited ent +#define addimplicit(f) { if(entgroup.empty() && enthover>=0) { entadd(enthover); undonext = (enthover != oldhover); f; entgroup.drop(); } else f; } #define entfocusv(i, f, v){ int n = efocus = (i); if(n>=0) { extentity &e = *v[n]; f; } } -#define entfocus(i, f) entfocusv(i, f, entities::getents()) +#define entfocus(i, f) entfocusv(i, f, entities::getents()) #define enteditv(i, f, v) \ { \ - entfocusv(i, \ - { \ - int oldtype = e.type; \ - removeentity(n); \ - f; \ - if(oldtype!=e.type) detachentity(e); \ - if(e.type!=ET_EMPTY) { addentity(n); if(oldtype!=e.type) attachentity(e); } \ - entities::editent(n, true); \ - }, v); \ + entfocusv(i, \ + { \ + int oldtype = e.type; \ + removeentity(n); \ + f; \ + if(oldtype!=e.type) detachentity(e); \ + if(e.type!=ET_EMPTY) { addentity(n); if(oldtype!=e.type) attachentity(e); } \ + entities::editent(n, true); \ + }, v); \ } #define entedit(i, f) enteditv(i, f, entities::getents()) #define addgroup(exp) { vector<extentity *> &ents = entities::getents(); loopv(ents) entfocusv(i, if(exp) entadd(n), ents); } @@ -418,93 +418,93 @@ void attachentities() #define groupeditloop(f){ vector<extentity *> &ents = entities::getents(); entlooplevel++; int _ = efocus; loopv(entgroup) enteditv(entgroup[i], f, ents); efocus = _; entlooplevel--; } #define groupeditpure(f){ if(entlooplevel>0) { entedit(efocus, f); } else groupeditloop(f); } #define groupeditundo(f){ makeundoent(); groupeditpure(f); } -#define groupedit(f) { addimplicit(groupeditundo(f)); } +#define groupedit(f) { addimplicit(groupeditundo(f)); } vec getselpos() { - vector<extentity *> &ents = entities::getents(); - if(entgroup.length() && ents.inrange(entgroup[0])) return ents[entgroup[0]]->o; - if(ents.inrange(enthover)) return ents[enthover]->o; - return vec(sel.o); + vector<extentity *> &ents = entities::getents(); + if(entgroup.length() && ents.inrange(entgroup[0])) return ents[entgroup[0]]->o; + if(ents.inrange(enthover)) return ents[enthover]->o; + return vec(sel.o); } undoblock *copyundoents(undoblock *u) { - entcancel(); - undoent *e = u->ents(); - loopi(u->numents) - entadd(e[i].i); - undoblock *c = newundoent(); + entcancel(); + undoent *e = u->ents(); + loopi(u->numents) + entadd(e[i].i); + undoblock *c = newundoent(); loopi(u->numents) if(e[i].e.type==ET_EMPTY) entgroup.removeobj(e[i].i); - return c; + return c; } void pasteundoent(int idx, const entity &ue) { - if(idx < 0 || idx >= MAXENTS) return; - vector<extentity *> &ents = entities::getents(); - while(ents.length() < idx) ents.add(entities::newentity())->type = ET_EMPTY; - int efocus = -1; - entedit(idx, (entity &)e = ue); + if(idx < 0 || idx >= MAXENTS) return; + vector<extentity *> &ents = entities::getents(); + while(ents.length() < idx) ents.add(entities::newentity())->type = ET_EMPTY; + int efocus = -1; + entedit(idx, (entity &)e = ue); } void pasteundoents(undoblock *u) { - undoent *ue = u->ents(); - loopi(u->numents) - entedit(ue[i].i, (entity &)e = ue[i].e); + undoent *ue = u->ents(); + loopi(u->numents) + entedit(ue[i].i, (entity &)e = ue[i].e); } void entflip() { - if(noentedit()) return; - int d = dimension(sel.orient); - float mid = sel.s[d]*sel.grid/2+sel.o[d]; - groupeditundo(e.o[d] -= (e.o[d]-mid)*2); + if(noentedit()) return; + int d = dimension(sel.orient); + float mid = sel.s[d]*sel.grid/2+sel.o[d]; + groupeditundo(e.o[d] -= (e.o[d]-mid)*2); } void entrotate(int *cw) { - if(noentedit()) return; - int d = dimension(sel.orient); - int dd = (*cw<0) == dimcoord(sel.orient) ? R[d] : C[d]; - float mid = sel.s[dd]*sel.grid/2+sel.o[dd]; - vec s(sel.o.v); - groupeditundo( - e.o[dd] -= (e.o[dd]-mid)*2; - e.o.sub(s); - swap(e.o[R[d]], e.o[C[d]]); - e.o.add(s); - ); + if(noentedit()) return; + int d = dimension(sel.orient); + int dd = (*cw<0) == dimcoord(sel.orient) ? R[d] : C[d]; + float mid = sel.s[dd]*sel.grid/2+sel.o[dd]; + vec s(sel.o.v); + groupeditundo( + e.o[dd] -= (e.o[dd]-mid)*2; + e.o.sub(s); + swap(e.o[R[d]], e.o[C[d]]); + e.o.add(s); + ); } void entselectionbox(const entity &e, vec &eo, vec &es) { - model *m = NULL; - const char *mname = entities::entmodel(e); - if(mname && (m = loadmodel(mname))) - { - m->collisionbox(eo, es); - if(es.x > es.y) es.y = es.x; else es.x = es.y; // square - es.z = (es.z + eo.z + 1 + entselradius)/2; // enclose ent radius box and model box - eo.x += e.o.x; - eo.y += e.o.y; - eo.z = e.o.z - entselradius + es.z; - } - else if(e.type == ET_MAPMODEL && (m = loadmapmodel(e.attr2))) - { - mmcollisionbox(e, m, eo, es); - es.max(entselradius); - eo.add(e.o); - } - else - { - es = vec(entselradius); - eo = e.o; - } - eo.sub(es); - es.mul(2); + model *m = NULL; + const char *mname = entities::entmodel(e); + if(mname && (m = loadmodel(mname))) + { + m->collisionbox(eo, es); + if(es.x > es.y) es.y = es.x; else es.x = es.y; // square + es.z = (es.z + eo.z + 1 + entselradius)/2; // enclose ent radius box and model box + eo.x += e.o.x; + eo.y += e.o.y; + eo.z = e.o.z - entselradius + es.z; + } + else if(e.type == ET_MAPMODEL && (m = loadmapmodel(e.attr2))) + { + mmcollisionbox(e, m, eo, es); + es.max(entselradius); + eo.add(e.o); + } + else + { + es = vec(entselradius); + eo = e.o; + } + eo.sub(es); + es.mul(2); } VAR(entselsnap, 0, 0, 1); @@ -519,327 +519,327 @@ int entmoving = 0; void entdrag(const vec &ray) { - if(noentedit() || !haveselent()) return; + if(noentedit() || !haveselent()) return; - float r = 0, c = 0; - static vec v, handle; - vec eo, es; - int d = dimension(entorient), - dc= dimcoord(entorient); + float r = 0, c = 0; + static vec v, handle; + vec eo, es; + int d = dimension(entorient), + dc= dimcoord(entorient); - entfocus(entgroup.last(), - entselectionbox(e, eo, es); + entfocus(entgroup.last(), + entselectionbox(e, eo, es); - if(!editmoveplane(e.o, ray, d, eo[d] + (dc ? es[d] : 0), handle, v, entmoving==1)) - return; + if(!editmoveplane(e.o, ray, d, eo[d] + (dc ? es[d] : 0), handle, v, entmoving==1)) + return; - ivec g(v); - int z = g[d]&(~(sel.grid-1)); - g.add(sel.grid/2).mask(~(sel.grid-1)); - g[d] = z; + ivec g(v); + int z = g[d]&(~(sel.grid-1)); + g.add(sel.grid/2).mask(~(sel.grid-1)); + g[d] = z; - r = (entselsnap ? g[R[d]] : v[R[d]]) - e.o[R[d]]; - c = (entselsnap ? g[C[d]] : v[C[d]]) - e.o[C[d]]; - ); + r = (entselsnap ? g[R[d]] : v[R[d]]) - e.o[R[d]]; + c = (entselsnap ? g[C[d]] : v[C[d]]) - e.o[C[d]]; + ); - if(entmoving==1) makeundoent(); - groupeditpure(e.o[R[d]] += r; e.o[C[d]] += c); - entmoving = 2; + if(entmoving==1) makeundoent(); + groupeditpure(e.o[R[d]] += r; e.o[C[d]] += c); + entmoving = 2; } VAR(showentradius, 0, 1, 1); void renderentring(const extentity &e, float radius, int axis) { - if(radius <= 0) return; - gle::defvertex(); - gle::begin(GL_LINE_LOOP); - loopi(15) - { - vec p(e.o); - const vec2 &sc = sincos360[i*(360/15)]; - p[axis>=2 ? 1 : 0] += radius*sc.x; - p[axis>=1 ? 2 : 1] += radius*sc.y; - gle::attrib(p); - } - xtraverts += gle::end(); + if(radius <= 0) return; + gle::defvertex(); + gle::begin(GL_LINE_LOOP); + loopi(15) + { + vec p(e.o); + const vec2 &sc = sincos360[i*(360/15)]; + p[axis>=2 ? 1 : 0] += radius*sc.x; + p[axis>=1 ? 2 : 1] += radius*sc.y; + gle::attrib(p); + } + xtraverts += gle::end(); } void renderentsphere(const extentity &e, float radius) { - if(radius <= 0) return; - loopk(3) renderentring(e, radius, k); + if(radius <= 0) return; + loopk(3) renderentring(e, radius, k); } void renderentattachment(const extentity &e) { - if(!e.attached) return; - gle::defvertex(); - gle::begin(GL_LINES); - gle::attrib(e.o); - gle::attrib(e.attached->o); - xtraverts += gle::end(); + if(!e.attached) return; + gle::defvertex(); + gle::begin(GL_LINES); + gle::attrib(e.o); + gle::attrib(e.attached->o); + xtraverts += gle::end(); } void renderentarrow(const extentity &e, const vec &dir, float radius) { - if(radius <= 0) return; - float arrowsize = min(radius/8, 0.5f); - vec target = vec(dir).mul(radius).add(e.o), arrowbase = vec(dir).mul(radius - arrowsize).add(e.o), spoke; - spoke.orthogonal(dir); - spoke.normalize(); - spoke.mul(arrowsize); + if(radius <= 0) return; + float arrowsize = min(radius/8, 0.5f); + vec target = vec(dir).mul(radius).add(e.o), arrowbase = vec(dir).mul(radius - arrowsize).add(e.o), spoke; + spoke.orthogonal(dir); + spoke.normalize(); + spoke.mul(arrowsize); - gle::defvertex(); + gle::defvertex(); - gle::begin(GL_LINES); - gle::attrib(e.o); - gle::attrib(target); - xtraverts += gle::end(); + gle::begin(GL_LINES); + gle::attrib(e.o); + gle::attrib(target); + xtraverts += gle::end(); - gle::begin(GL_TRIANGLE_FAN); - gle::attrib(target); - loopi(5) gle::attrib(vec(spoke).rotate(2*M_PI*i/4.0f, dir).add(arrowbase)); - xtraverts += gle::end(); + gle::begin(GL_TRIANGLE_FAN); + gle::attrib(target); + loopi(5) gle::attrib(vec(spoke).rotate(2*M_PI*i/4.0f, dir).add(arrowbase)); + xtraverts += gle::end(); } void renderentcone(const extentity &e, const vec &dir, float radius, float angle) { - if(radius <= 0) return; - vec spot = vec(dir).mul(radius*cosf(angle*RAD)).add(e.o), spoke; - spoke.orthogonal(dir); - spoke.normalize(); - spoke.mul(radius*sinf(angle*RAD)); + if(radius <= 0) return; + vec spot = vec(dir).mul(radius*cosf(angle*RAD)).add(e.o), spoke; + spoke.orthogonal(dir); + spoke.normalize(); + spoke.mul(radius*sinf(angle*RAD)); - gle::defvertex(); + gle::defvertex(); - gle::begin(GL_LINES); - loopi(8) - { - gle::attrib(e.o); - gle::attrib(vec(spoke).rotate(2*M_PI*i/8.0f, dir).add(spot)); - } - xtraverts += gle::end(); + gle::begin(GL_LINES); + loopi(8) + { + gle::attrib(e.o); + gle::attrib(vec(spoke).rotate(2*M_PI*i/8.0f, dir).add(spot)); + } + xtraverts += gle::end(); - gle::begin(GL_LINE_LOOP); - loopi(8) gle::attrib(vec(spoke).rotate(2*M_PI*i/8.0f, dir).add(spot)); - xtraverts += gle::end(); + gle::begin(GL_LINE_LOOP); + loopi(8) gle::attrib(vec(spoke).rotate(2*M_PI*i/8.0f, dir).add(spot)); + xtraverts += gle::end(); } void renderentradius(extentity &e, bool color) { - switch(e.type) - { - case ET_LIGHT: - if(color) gle::colorf(e.attr2/255.0f, e.attr3/255.0f, e.attr4/255.0f); - renderentsphere(e, e.attr1); - break; - - case ET_SPOTLIGHT: - if(e.attached) - { - if(color) gle::colorf(0, 1, 1); - float radius = e.attached->attr1; - if(!radius) radius = 2*e.o.dist(e.attached->o); - vec dir = vec(e.o).sub(e.attached->o).normalize(); - float angle = clamp(int(e.attr1), 1, 89); - renderentattachment(e); - renderentcone(*e.attached, dir, radius, angle); - } - break; - - case ET_SOUND: - if(color) gle::colorf(0, 1, 1); - renderentsphere(e, e.attr2); - break; - - case ET_ENVMAP: - { - extern int envmapradius; - if(color) gle::colorf(0, 1, 1); - renderentsphere(e, e.attr1 ? max(0, min(10000, int(e.attr1))) : envmapradius); - break; - } - - case ET_MAPMODEL: - case ET_PLAYERSTART: - { - if(color) gle::colorf(0, 1, 1); - entities::entradius(e, color); - vec dir; - vecfromyawpitch(e.attr1, 0, 1, 0, dir); - renderentarrow(e, dir, 4); - break; - } - - default: - if(e.type>=ET_GAMESPECIFIC) - { - if(color) gle::colorf(0, 1, 1); - entities::entradius(e, color); - } - break; - } + switch(e.type) + { + case ET_LIGHT: + if(color) gle::colorf(e.attr2/255.0f, e.attr3/255.0f, e.attr4/255.0f); + renderentsphere(e, e.attr1); + break; + + case ET_SPOTLIGHT: + if(e.attached) + { + if(color) gle::colorf(0, 1, 1); + float radius = e.attached->attr1; + if(!radius) radius = 2*e.o.dist(e.attached->o); + vec dir = vec(e.o).sub(e.attached->o).normalize(); + float angle = clamp(int(e.attr1), 1, 89); + renderentattachment(e); + renderentcone(*e.attached, dir, radius, angle); + } + break; + + case ET_SOUND: + if(color) gle::colorf(0, 1, 1); + renderentsphere(e, e.attr2); + break; + + case ET_ENVMAP: + { + extern int envmapradius; + if(color) gle::colorf(0, 1, 1); + renderentsphere(e, e.attr1 ? max(0, min(10000, int(e.attr1))) : envmapradius); + break; + } + + case ET_MAPMODEL: + case ET_PLAYERSTART: + { + if(color) gle::colorf(0, 1, 1); + entities::entradius(e, color); + vec dir; + vecfromyawpitch(e.attr1, 0, 1, 0, dir); + renderentarrow(e, dir, 4); + break; + } + + default: + if(e.type>=ET_GAMESPECIFIC) + { + if(color) gle::colorf(0, 1, 1); + entities::entradius(e, color); + } + break; + } } static void renderentbox(const vec &eo, vec es) { - es.add(eo); + es.add(eo); - // bottom quad - gle::attrib(eo.x, eo.y, eo.z); gle::attrib(es.x, eo.y, eo.z); - gle::attrib(es.x, eo.y, eo.z); gle::attrib(es.x, es.y, eo.z); - gle::attrib(es.x, es.y, eo.z); gle::attrib(eo.x, es.y, eo.z); - gle::attrib(eo.x, es.y, eo.z); gle::attrib(eo.x, eo.y, eo.z); + // bottom quad + gle::attrib(eo.x, eo.y, eo.z); gle::attrib(es.x, eo.y, eo.z); + gle::attrib(es.x, eo.y, eo.z); gle::attrib(es.x, es.y, eo.z); + gle::attrib(es.x, es.y, eo.z); gle::attrib(eo.x, es.y, eo.z); + gle::attrib(eo.x, es.y, eo.z); gle::attrib(eo.x, eo.y, eo.z); - // top quad - gle::attrib(eo.x, eo.y, es.z); gle::attrib(es.x, eo.y, es.z); - gle::attrib(es.x, eo.y, es.z); gle::attrib(es.x, es.y, es.z); - gle::attrib(es.x, es.y, es.z); gle::attrib(eo.x, es.y, es.z); - gle::attrib(eo.x, es.y, es.z); gle::attrib(eo.x, eo.y, es.z); + // top quad + gle::attrib(eo.x, eo.y, es.z); gle::attrib(es.x, eo.y, es.z); + gle::attrib(es.x, eo.y, es.z); gle::attrib(es.x, es.y, es.z); + gle::attrib(es.x, es.y, es.z); gle::attrib(eo.x, es.y, es.z); + gle::attrib(eo.x, es.y, es.z); gle::attrib(eo.x, eo.y, es.z); - // sides - gle::attrib(eo.x, eo.y, eo.z); gle::attrib(eo.x, eo.y, es.z); - gle::attrib(es.x, eo.y, eo.z); gle::attrib(es.x, eo.y, es.z); - gle::attrib(es.x, es.y, eo.z); gle::attrib(es.x, es.y, es.z); - gle::attrib(eo.x, es.y, eo.z); gle::attrib(eo.x, es.y, es.z); + // sides + gle::attrib(eo.x, eo.y, eo.z); gle::attrib(eo.x, eo.y, es.z); + gle::attrib(es.x, eo.y, eo.z); gle::attrib(es.x, eo.y, es.z); + gle::attrib(es.x, es.y, eo.z); gle::attrib(es.x, es.y, es.z); + gle::attrib(eo.x, es.y, eo.z); gle::attrib(eo.x, es.y, es.z); } void renderentselection(const vec &o, const vec &ray, bool entmoving) { - if(noentedit()) return; - vec eo, es; - - if(entgroup.length()) - { - gle::colorub(0, 40, 0); - gle::defvertex(); - gle::begin(GL_LINES, entgroup.length()*24); - loopv(entgroup) entfocus(entgroup[i], - entselectionbox(e, eo, es); - renderentbox(eo, es); - ); - xtraverts += gle::end(); - } - - if(enthover >= 0) - { - gle::colorub(0, 40, 0); - entfocus(enthover, entselectionbox(e, eo, es)); // also ensures enthover is back in focus - boxs3D(eo, es, 1); - if(entmoving && entmovingshadow==1) - { - vec a, b; - gle::colorub(20, 20, 20); - (a = eo).x = eo.x - fmod(eo.x, worldsize); (b = es).x = a.x + worldsize; boxs3D(a, b, 1); - (a = eo).y = eo.y - fmod(eo.y, worldsize); (b = es).y = a.x + worldsize; boxs3D(a, b, 1); - (a = eo).z = eo.z - fmod(eo.z, worldsize); (b = es).z = a.x + worldsize; boxs3D(a, b, 1); - } - gle::colorub(150,0,0); - boxs(entorient, eo, es); - boxs(entorient, eo, es, clamp(0.015f*camera1->o.dist(eo)*tan(fovy*0.5f*RAD), 0.1f, 1.0f)); - } - - if(showentradius && (entgroup.length() || enthover >= 0)) - { - glDepthFunc(GL_GREATER); - gle::colorf(0.25f, 0.25f, 0.25f); - loopv(entgroup) entfocus(entgroup[i], renderentradius(e, false)); - if(enthover>=0) entfocus(enthover, renderentradius(e, false)); - glDepthFunc(GL_LESS); - loopv(entgroup) entfocus(entgroup[i], renderentradius(e, true)); - if(enthover>=0) entfocus(enthover, renderentradius(e, true)); - } + if(noentedit()) return; + vec eo, es; + + if(entgroup.length()) + { + gle::colorub(0, 40, 0); + gle::defvertex(); + gle::begin(GL_LINES, entgroup.length()*24); + loopv(entgroup) entfocus(entgroup[i], + entselectionbox(e, eo, es); + renderentbox(eo, es); + ); + xtraverts += gle::end(); + } + + if(enthover >= 0) + { + gle::colorub(0, 40, 0); + entfocus(enthover, entselectionbox(e, eo, es)); // also ensures enthover is back in focus + boxs3D(eo, es, 1); + if(entmoving && entmovingshadow==1) + { + vec a, b; + gle::colorub(20, 20, 20); + (a = eo).x = eo.x - fmod(eo.x, worldsize); (b = es).x = a.x + worldsize; boxs3D(a, b, 1); + (a = eo).y = eo.y - fmod(eo.y, worldsize); (b = es).y = a.x + worldsize; boxs3D(a, b, 1); + (a = eo).z = eo.z - fmod(eo.z, worldsize); (b = es).z = a.x + worldsize; boxs3D(a, b, 1); + } + gle::colorub(150,0,0); + boxs(entorient, eo, es); + boxs(entorient, eo, es, clamp(0.015f*camera1->o.dist(eo)*tan(fovy*0.5f*RAD), 0.1f, 1.0f)); + } + + if(showentradius && (entgroup.length() || enthover >= 0)) + { + glDepthFunc(GL_GREATER); + gle::colorf(0.25f, 0.25f, 0.25f); + loopv(entgroup) entfocus(entgroup[i], renderentradius(e, false)); + if(enthover>=0) entfocus(enthover, renderentradius(e, false)); + glDepthFunc(GL_LESS); + loopv(entgroup) entfocus(entgroup[i], renderentradius(e, true)); + if(enthover>=0) entfocus(enthover, renderentradius(e, true)); + } } bool enttoggle(int id) { - undonext = true; - int i = entgroup.find(id); - if(i < 0) - entadd(id); - else - entgroup.remove(i); - return i < 0; + undonext = true; + int i = entgroup.find(id); + if(i < 0) + entadd(id); + else + entgroup.remove(i); + return i < 0; } bool hoveringonent(int ent, int orient) { - if(noentedit()) return false; - entorient = orient; - if((efocus = enthover = ent) >= 0) - return true; - efocus = entgroup.empty() ? -1 : entgroup.last(); - enthover = -1; - return false; + if(noentedit()) return false; + entorient = orient; + if((efocus = enthover = ent) >= 0) + return true; + efocus = entgroup.empty() ? -1 : entgroup.last(); + enthover = -1; + return false; } VAR(entitysurf, 0, 0, 1); ICOMMAND(entadd, "", (), { - if(enthover >= 0 && !noentedit()) - { - if(entgroup.find(enthover) < 0) entadd(enthover); - if(entmoving > 1) entmoving = 1; - } + if(enthover >= 0 && !noentedit()) + { + if(entgroup.find(enthover) < 0) entadd(enthover); + if(entmoving > 1) entmoving = 1; + } }); ICOMMAND(enttoggle, "", (), { - if(enthover < 0 || noentedit() || !enttoggle(enthover)) { entmoving = 0; intret(0); } - else { if(entmoving > 1) entmoving = 1; intret(1); } + if(enthover < 0 || noentedit() || !enttoggle(enthover)) { entmoving = 0; intret(0); } + else { if(entmoving > 1) entmoving = 1; intret(1); } }); ICOMMAND(entmoving, "b", (int *n), { - if(*n >= 0) - { - if(!*n || enthover < 0 || noentedit()) entmoving = 0; - else - { - if(entgroup.find(enthover) < 0) { entadd(enthover); entmoving = 1; } - else if(!entmoving) entmoving = 1; - } - } - intret(entmoving); + if(*n >= 0) + { + if(!*n || enthover < 0 || noentedit()) entmoving = 0; + else + { + if(entgroup.find(enthover) < 0) { entadd(enthover); entmoving = 1; } + else if(!entmoving) entmoving = 1; + } + } + intret(entmoving); }); void entpush(int *dir) { - if(noentedit()) return; - int d = dimension(entorient); - int s = dimcoord(entorient) ? -*dir : *dir; - if(entmoving) - { - groupeditpure(e.o[d] += float(s*sel.grid)); // editdrag supplies the undo - } - else - groupedit(e.o[d] += float(s*sel.grid)); - if(entitysurf==1) - { - player->o[d] += float(s*sel.grid); - player->resetinterp(); - } + if(noentedit()) return; + int d = dimension(entorient); + int s = dimcoord(entorient) ? -*dir : *dir; + if(entmoving) + { + groupeditpure(e.o[d] += float(s*sel.grid)); // editdrag supplies the undo + } + else + groupedit(e.o[d] += float(s*sel.grid)); + if(entitysurf==1) + { + player->o[d] += float(s*sel.grid); + player->resetinterp(); + } } VAR(entautoviewdist, 0, 25, 100); void entautoview(int *dir) { - if(!haveselent()) return; - static int s = 0; - vec v(player->o); - v.sub(worldpos); - v.normalize(); - v.mul(entautoviewdist); - int t = s + *dir; - s = abs(t) % entgroup.length(); - if(t<0 && s>0) s = entgroup.length() - s; - entfocus(entgroup[s], - v.add(e.o); - player->o = v; - player->resetinterp(); - ); + if(!haveselent()) return; + static int s = 0; + vec v(player->o); + v.sub(worldpos); + v.normalize(); + v.mul(entautoviewdist); + int t = s + *dir; + s = abs(t) % entgroup.length(); + if(t<0 && s>0) s = entgroup.length() - s; + entfocus(entgroup[s], + v.add(e.o); + player->o = v; + player->resetinterp(); + ); } COMMAND(entautoview, "i"); @@ -849,76 +849,76 @@ COMMAND(entpush, "i"); void delent() { - if(noentedit()) return; - groupedit(e.type = ET_EMPTY;); - entcancel(); + if(noentedit()) return; + groupedit(e.type = ET_EMPTY;); + entcancel(); } int findtype(char *what) { - for(int i = 0; *entities::entname(i); i++) if(strcmp(what, entities::entname(i))==0) return i; - conoutf(CON_ERROR, "unknown entity type \"%s\"", what); - return ET_EMPTY; + for(int i = 0; *entities::entname(i); i++) if(strcmp(what, entities::entname(i))==0) return i; + conoutf(CON_ERROR, "unknown entity type \"%s\"", what); + return ET_EMPTY; } VAR(entdrop, 0, 2, 3); bool dropentity(entity &e, int drop = -1) { - vec radius(4.0f, 4.0f, 4.0f); - if(drop<0) drop = entdrop; - if(e.type == ET_MAPMODEL) - { - model *m = loadmapmodel(e.attr2); - if(m) - { - vec center; - mmboundbox(e, m, center, radius); - radius.x += fabs(center.x); - radius.y += fabs(center.y); - } - radius.z = 0.0f; - } - switch(drop) - { - case 1: - if(e.type != ET_LIGHT && e.type != ET_SPOTLIGHT) - dropenttofloor(&e); - break; - case 2: - case 3: - int cx = 0, cy = 0; - if(sel.cxs == 1 && sel.cys == 1) - { - cx = (sel.cx ? 1 : -1) * sel.grid / 2; - cy = (sel.cy ? 1 : -1) * sel.grid / 2; - } - e.o = vec(sel.o); - int d = dimension(sel.orient), dc = dimcoord(sel.orient); - e.o[R[d]] += sel.grid / 2 + cx; - e.o[C[d]] += sel.grid / 2 + cy; - if(!dc) - e.o[D[d]] -= radius[D[d]]; - else - e.o[D[d]] += sel.grid + radius[D[d]]; - - if(drop == 3) - dropenttofloor(&e); - break; - } - return true; + vec radius(4.0f, 4.0f, 4.0f); + if(drop<0) drop = entdrop; + if(e.type == ET_MAPMODEL) + { + model *m = loadmapmodel(e.attr2); + if(m) + { + vec center; + mmboundbox(e, m, center, radius); + radius.x += fabs(center.x); + radius.y += fabs(center.y); + } + radius.z = 0.0f; + } + switch(drop) + { + case 1: + if(e.type != ET_LIGHT && e.type != ET_SPOTLIGHT) + dropenttofloor(&e); + break; + case 2: + case 3: + int cx = 0, cy = 0; + if(sel.cxs == 1 && sel.cys == 1) + { + cx = (sel.cx ? 1 : -1) * sel.grid / 2; + cy = (sel.cy ? 1 : -1) * sel.grid / 2; + } + e.o = vec(sel.o); + int d = dimension(sel.orient), dc = dimcoord(sel.orient); + e.o[R[d]] += sel.grid / 2 + cx; + e.o[C[d]] += sel.grid / 2 + cy; + if(!dc) + e.o[D[d]] -= radius[D[d]]; + else + e.o[D[d]] += sel.grid + radius[D[d]]; + + if(drop == 3) + dropenttofloor(&e); + break; + } + return true; } void dropent() { - if(noentedit()) return; - groupedit(dropentity(e)); + if(noentedit()) return; + groupedit(dropentity(e)); } void attachent() { - if(noentedit()) return; - groupedit(attachentity(e)); + if(noentedit()) return; + groupedit(attachentity(e)); } COMMAND(attachent, ""); @@ -929,63 +929,63 @@ static int keepents = 0; extentity *newentity(bool local, const vec &o, int type, int v1, int v2, int v3, int v4, int v5, int &idx) { - vector<extentity *> &ents = entities::getents(); - if(local) - { - idx = -1; - for(int i = keepents; i < ents.length(); i++) if(ents[i]->type == ET_EMPTY) { idx = i; break; } - if(idx < 0 && ents.length() >= MAXENTS) { conoutf(CON_ERROR, "too many entities"); return NULL; } - } - else while(ents.length() < idx) ents.add(entities::newentity())->type = ET_EMPTY; - extentity &e = *entities::newentity(); - e.o = o; - e.attr1 = v1; - e.attr2 = v2; - e.attr3 = v3; - e.attr4 = v4; - e.attr5 = v5; - e.type = type; - e.reserved = 0; - e.light.color = vec(1, 1, 1); - e.light.dir = vec(0, 0, 1); - if(local) - { - if(entcamdir) switch(type) - { - case ET_MAPMODEL: - case ET_PLAYERSTART: - e.attr5 = e.attr4; - e.attr4 = e.attr3; - e.attr3 = e.attr2; - e.attr2 = e.attr1; - e.attr1 = (int)camera1->yaw; - break; - } - entities::fixentity(e); - } - if(ents.inrange(idx)) { entities::deleteentity(ents[idx]); ents[idx] = &e; } - else { idx = ents.length(); ents.add(&e); } - return &e; + vector<extentity *> &ents = entities::getents(); + if(local) + { + idx = -1; + for(int i = keepents; i < ents.length(); i++) if(ents[i]->type == ET_EMPTY) { idx = i; break; } + if(idx < 0 && ents.length() >= MAXENTS) { conoutf(CON_ERROR, "too many entities"); return NULL; } + } + else while(ents.length() < idx) ents.add(entities::newentity())->type = ET_EMPTY; + extentity &e = *entities::newentity(); + e.o = o; + e.attr1 = v1; + e.attr2 = v2; + e.attr3 = v3; + e.attr4 = v4; + e.attr5 = v5; + e.type = type; + e.reserved = 0; + e.light.color = vec(1, 1, 1); + e.light.dir = vec(0, 0, 1); + if(local) + { + if(entcamdir) switch(type) + { + case ET_MAPMODEL: + case ET_PLAYERSTART: + e.attr5 = e.attr4; + e.attr4 = e.attr3; + e.attr3 = e.attr2; + e.attr2 = e.attr1; + e.attr1 = (int)camera1->yaw; + break; + } + entities::fixentity(e); + } + if(ents.inrange(idx)) { entities::deleteentity(ents[idx]); ents[idx] = &e; } + else { idx = ents.length(); ents.add(&e); } + return &e; } void newentity(int type, int a1, int a2, int a3, int a4, int a5) { - int idx; - extentity *t = newentity(true, player->o, type, a1, a2, a3, a4, a5, idx); - if(!t) return; - dropentity(*t); - t->type = ET_EMPTY; - enttoggle(idx); - makeundoent(); - entedit(idx, e.type = type); + int idx; + extentity *t = newentity(true, player->o, type, a1, a2, a3, a4, a5, idx); + if(!t) return; + dropentity(*t); + t->type = ET_EMPTY; + enttoggle(idx); + makeundoent(); + entedit(idx, e.type = type); } void newent(char *what, int *a1, int *a2, int *a3, int *a4, int *a5) { - if(noentedit()) return; - int type = findtype(what); - if(type != ET_EMPTY) - newentity(type, *a1, *a2, *a3, *a4, *a5); + if(noentedit()) return; + int type = findtype(what); + if(type != ET_EMPTY) + newentity(type, *a1, *a2, *a3, *a4, *a5); } int entcopygrid; @@ -993,33 +993,33 @@ vector<entity> entcopybuf; void entcopy() { - if(noentedit()) return; - entcopygrid = sel.grid; - entcopybuf.shrink(0); - loopv(entgroup) - entfocus(entgroup[i], entcopybuf.add(e).o.sub(vec(sel.o))); + if(noentedit()) return; + entcopygrid = sel.grid; + entcopybuf.shrink(0); + loopv(entgroup) + entfocus(entgroup[i], entcopybuf.add(e).o.sub(vec(sel.o))); } void entpaste() { - if(noentedit()) return; - if(entcopybuf.length()==0) return; - entcancel(); - float m = float(sel.grid)/float(entcopygrid); - loopv(entcopybuf) - { - entity &c = entcopybuf[i]; - vec o(c.o); - o.mul(m).add(vec(sel.o)); - int idx; - extentity *e = newentity(true, o, ET_EMPTY, c.attr1, c.attr2, c.attr3, c.attr4, c.attr5, idx); - if(!e) continue; - entadd(idx); - keepents = max(keepents, idx+1); - } - keepents = 0; - int j = 0; - groupeditundo(e.type = entcopybuf[j++].type;); + if(noentedit()) return; + if(entcopybuf.length()==0) return; + entcancel(); + float m = float(sel.grid)/float(entcopygrid); + loopv(entcopybuf) + { + entity &c = entcopybuf[i]; + vec o(c.o); + o.mul(m).add(vec(sel.o)); + int idx; + extentity *e = newentity(true, o, ET_EMPTY, c.attr1, c.attr2, c.attr3, c.attr4, c.attr5, idx); + if(!e) continue; + entadd(idx); + keepents = max(keepents, idx+1); + } + keepents = 0; + int j = 0; + groupeditundo(e.type = entcopybuf[j++].type;); } COMMAND(newent, "siiiii"); @@ -1030,101 +1030,101 @@ COMMAND(entpaste, ""); void entset(char *what, int *a1, int *a2, int *a3, int *a4, int *a5) { - if(noentedit()) return; - int type = findtype(what); - if(type != ET_EMPTY) - groupedit(e.type=type; - e.attr1=*a1; - e.attr2=*a2; - e.attr3=*a3; - e.attr4=*a4; - e.attr5=*a5); + if(noentedit()) return; + int type = findtype(what); + if(type != ET_EMPTY) + groupedit(e.type=type; + e.attr1=*a1; + e.attr2=*a2; + e.attr3=*a3; + e.attr4=*a4; + e.attr5=*a5); } void printent(extentity &e, char *buf, int len) { - switch(e.type) - { - case ET_PARTICLES: - if(printparticles(e, buf, len)) return; - break; + switch(e.type) + { + case ET_PARTICLES: + if(printparticles(e, buf, len)) return; + break; - default: - if(e.type >= ET_GAMESPECIFIC && entities::printent(e, buf, len)) return; - break; - } - nformatstring(buf, len, "%s %d %d %d %d %d", entities::entname(e.type), e.attr1, e.attr2, e.attr3, e.attr4, e.attr5); + default: + if(e.type >= ET_GAMESPECIFIC && entities::printent(e, buf, len)) return; + break; + } + nformatstring(buf, len, "%s %d %d %d %d %d", entities::entname(e.type), e.attr1, e.attr2, e.attr3, e.attr4, e.attr5); } void nearestent() { - if(noentedit()) return; - int closest = -1; - float closedist = 1e16f; - vector<extentity *> &ents = entities::getents(); - loopv(ents) - { - extentity &e = *ents[i]; - if(e.type == ET_EMPTY) continue; - float dist = e.o.dist(player->o); - if(dist < closedist) - { - closest = i; - closedist = dist; - } - } - if(closest >= 0 && entgroup.find(closest) < 0) entadd(closest); + if(noentedit()) return; + int closest = -1; + float closedist = 1e16f; + vector<extentity *> &ents = entities::getents(); + loopv(ents) + { + extentity &e = *ents[i]; + if(e.type == ET_EMPTY) continue; + float dist = e.o.dist(player->o); + if(dist < closedist) + { + closest = i; + closedist = dist; + } + } + if(closest >= 0 && entgroup.find(closest) < 0) entadd(closest); } ICOMMAND(enthavesel,"", (), addimplicit(intret(entgroup.length()))); ICOMMAND(entselect, "e", (uint *body), if(!noentedit()) addgroup(e.type != ET_EMPTY && entgroup.find(n)<0 && executebool(body))); ICOMMAND(entloop, "e", (uint *body), if(!noentedit()) addimplicit(groupeditloop(((void)e, execute(body))))); -ICOMMAND(insel, "", (), entfocus(efocus, intret(pointinsel(sel, e.o)))); -ICOMMAND(entget, "", (), entfocus(efocus, string s; printent(e, s, sizeof(s)); result(s))); +ICOMMAND(insel, "", (), entfocus(efocus, intret(pointinsel(sel, e.o)))); +ICOMMAND(entget, "", (), entfocus(efocus, string s; printent(e, s, sizeof(s)); result(s))); ICOMMAND(entindex, "", (), intret(efocus)); COMMAND(entset, "siiiii"); COMMAND(nearestent, ""); void enttype(char *type, int *numargs) { - if(*numargs >= 1) - { - int typeidx = findtype(type); - if(typeidx != ET_EMPTY) groupedit(e.type = typeidx); - } - else entfocus(efocus, - { - result(entities::entname(e.type)); - }) + if(*numargs >= 1) + { + int typeidx = findtype(type); + if(typeidx != ET_EMPTY) groupedit(e.type = typeidx); + } + else entfocus(efocus, + { + result(entities::entname(e.type)); + }) } void entattr(int *attr, int *val, int *numargs) { - if(*numargs >= 2) - { - if(*attr >= 0 && *attr <= 4) - groupedit( - switch(*attr) - { - case 0: e.attr1 = *val; break; - case 1: e.attr2 = *val; break; - case 2: e.attr3 = *val; break; - case 3: e.attr4 = *val; break; - case 4: e.attr5 = *val; break; - } - ); - } - else entfocus(efocus, - { - switch(*attr) - { - case 0: intret(e.attr1); break; - case 1: intret(e.attr2); break; - case 2: intret(e.attr3); break; - case 3: intret(e.attr4); break; - case 4: intret(e.attr5); break; - } - }); + if(*numargs >= 2) + { + if(*attr >= 0 && *attr <= 4) + groupedit( + switch(*attr) + { + case 0: e.attr1 = *val; break; + case 1: e.attr2 = *val; break; + case 2: e.attr3 = *val; break; + case 3: e.attr4 = *val; break; + case 4: e.attr5 = *val; break; + } + ); + } + else entfocus(efocus, + { + switch(*attr) + { + case 0: intret(e.attr1); break; + case 1: intret(e.attr2); break; + case 2: intret(e.attr3); break; + case 3: intret(e.attr4); break; + case 4: intret(e.attr5); break; + } + }); } COMMAND(enttype, "sN"); @@ -1132,21 +1132,21 @@ COMMAND(entattr, "iiN"); int findentity(int type, int index, int attr1, int attr2) { - const vector<extentity *> &ents = entities::getents(); - if(index > ents.length()) index = ents.length(); - else for(int i = index; i<ents.length(); i++) - { - extentity &e = *ents[i]; - if(e.type==type && (attr1<0 || e.attr1==attr1) && (attr2<0 || e.attr2==attr2)) - return i; - } - loopj(index) - { - extentity &e = *ents[j]; - if(e.type==type && (attr1<0 || e.attr1==attr1) && (attr2<0 || e.attr2==attr2)) - return j; - } - return -1; + const vector<extentity *> &ents = entities::getents(); + if(index > ents.length()) index = ents.length(); + else for(int i = index; i<ents.length(); i++) + { + extentity &e = *ents[i]; + if(e.type==type && (attr1<0 || e.attr1==attr1) && (attr2<0 || e.attr2==attr2)) + return i; + } + loopj(index) + { + extentity &e = *ents[j]; + if(e.type==type && (attr1<0 || e.attr1==attr1) && (attr2<0 || e.attr2==attr2)) + return j; + } + return -1; } struct spawninfo { const extentity *e; float weight; }; @@ -1155,18 +1155,18 @@ struct spawninfo { const extentity *e; float weight; }; // which serves as a measure of its desirability for a spawning player. float gatherspawninfos(dynent *d, int tag, vector<spawninfo> &spawninfos) { - const vector<extentity *> &ents = entities::getents(); - float total = 0.0f; - loopv(ents) - { - const extentity &e = *ents[i]; - if(e.type != ET_PLAYERSTART || e.attr2 != tag) continue; - spawninfo &s = spawninfos.add(); - s.e = &e; - s.weight = game::ratespawn(d, e); - total += s.weight; - } - return total; + const vector<extentity *> &ents = entities::getents(); + float total = 0.0f; + loopv(ents) + { + const extentity &e = *ents[i]; + if(e.type != ET_PLAYERSTART || e.attr2 != tag) continue; + spawninfo &s = spawninfos.add(); + s.e = &e; + s.weight = game::ratespawn(d, e); + total += s.weight; + } + return total; } // Randomly picks a weighted spawn from the provided vector and removes it. @@ -1174,179 +1174,178 @@ float gatherspawninfos(dynent *d, int tag, vector<spawninfo> &spawninfos) // If all weights are zero, the index is picked uniformly. static const extentity *poprandomspawn(vector<spawninfo> &spawninfos, float &total) { - if(spawninfos.empty()) return NULL; - int index = 0; - if(total > 0.0f) - { - float x = rndscale(total); - do x -= spawninfos[index].weight; while(x > 0 && ++index < spawninfos.length()-1); - } - else index = rnd(spawninfos.length()); - spawninfo s = spawninfos.removeunordered(index); - total -= s.weight; - return s.e; + if(spawninfos.empty()) return NULL; + int index = 0; + if(total > 0.0f) + { + float x = rndscale(total); + do x -= spawninfos[index].weight; while(x > 0 && ++index < spawninfos.length()-1); + } + else index = rnd(spawninfos.length()); + spawninfo s = spawninfos.removeunordered(index); + total -= s.weight; + return s.e; } static inline bool tryspawn(dynent *d, const extentity &e) { - d->o = e.o; - d->yaw = e.attr1; - return entinmap(d, true); + d->o = e.o; + d->yaw = e.attr1; + return entinmap(d, true); } void findplayerspawn(dynent *d, int forceent, int tag) { - const vector<extentity *> &ents = entities::getents(); - d->pitch = 0; - d->roll = 0; - if(ents.inrange(forceent) && tryspawn(d, *ents[forceent])) return; - vector<spawninfo> spawninfos; - float total = gatherspawninfos(d, tag, spawninfos); - while(const extentity *e = poprandomspawn(spawninfos, total)) if(tryspawn(d, *e)) return; - d->o = vec(0.5f * worldsize).addz(1); - d->yaw = 0; - entinmap(d); + const vector<extentity *> &ents = entities::getents(); + d->pitch = 0; + d->roll = 0; + if(ents.inrange(forceent) && tryspawn(d, *ents[forceent])) return; + vector<spawninfo> spawninfos; + float total = gatherspawninfos(d, tag, spawninfos); + while(const extentity *e = poprandomspawn(spawninfos, total)) if(tryspawn(d, *e)) return; + d->o = vec(0.5f * worldsize).addz(1); + d->yaw = 0; + entinmap(d); } void splitocta(cube *c, int size) { - if(size <= 0x1000) return; - loopi(8) - { - if(!c[i].children) c[i].children = newcubes(isempty(c[i]) ? F_EMPTY : F_SOLID); - splitocta(c[i].children, size>>1); - } + if(size <= 0x1000) return; + loopi(8) + { + if(!c[i].children) c[i].children = newcubes(isempty(c[i]) ? F_EMPTY : F_SOLID); + splitocta(c[i].children, size>>1); + } } void resetmap() { - clearoverrides(); - clearmapsounds(); - cleanreflections(); - resetblendmap(); - resetlightmaps(); - clearslots(); - clearparticles(); - cleardecals(); - cleardamagescreen(); - clearsleep(); - cancelsel(); - pruneundos(); - clearmapcrc(); + clearoverrides(); + clearmapsounds(); + cleanreflections(); + resetblendmap(); + resetlightmaps(); + clearslots(); + clearparticles(); + cleardecals(); + clearsleep(); + cancelsel(); + pruneundos(); + clearmapcrc(); - entities::clearents(); - outsideents.setsize(0); + entities::clearents(); + outsideents.setsize(0); } void startmap(const char *name) { - game::startmap(name); + game::startmap(name); } -bool emptymap(int scale, bool force, const char *mname, bool usecfg) // main empty world creation routine +bool emptymap(int scale, bool force, const char *mname, bool usecfg) // main empty world creation routine { - if(!force && !editmode) - { - conoutf(CON_ERROR, "newmap only allowed in edit mode"); - return false; - } + if(!force && !editmode) + { + conoutf(CON_ERROR, "newmap only allowed in edit mode"); + return false; + } - resetmap(); + resetmap(); - setvar("mapscale", scale<10 ? 10 : (scale>16 ? 16 : scale), true, false); - setvar("mapsize", 1<<worldscale, true, false); + setvar("mapscale", scale<10 ? 10 : (scale>16 ? 16 : scale), true, false); + setvar("mapsize", 1<<worldscale, true, false); - texmru.shrink(0); - freeocta(worldroot); - worldroot = newcubes(F_EMPTY); - loopi(4) solidfaces(worldroot[i]); + texmru.shrink(0); + freeocta(worldroot); + worldroot = newcubes(F_EMPTY); + loopi(4) solidfaces(worldroot[i]); - if(worldsize > 0x1000) splitocta(worldroot, worldsize>>1); + if(worldsize > 0x1000) splitocta(worldroot, worldsize>>1); - clearmainmenu(); + clearmainmenu(); - if(usecfg) - { - identflags |= IDF_OVERRIDDEN; - execfile("data/default_map.cfg", false); - identflags &= ~IDF_OVERRIDDEN; - } + if(usecfg) + { + identflags |= IDF_OVERRIDDEN; + execfile("data/default_map.cfg", false); + identflags &= ~IDF_OVERRIDDEN; + } - initlights(); - allchanged(true); + initlights(); + allchanged(true); - startmap(mname); + startmap(mname); - return true; + return true; } bool enlargemap(bool force) { - if(!force && !editmode) - { - conoutf(CON_ERROR, "mapenlarge only allowed in edit mode"); - return false; - } - if(worldsize >= 1<<16) return false; + if(!force && !editmode) + { + conoutf(CON_ERROR, "mapenlarge only allowed in edit mode"); + return false; + } + if(worldsize >= 1<<16) return false; - while(outsideents.length()) removeentity(outsideents.pop()); + while(outsideents.length()) removeentity(outsideents.pop()); - worldscale++; - worldsize *= 2; - cube *c = newcubes(F_EMPTY); - c[0].children = worldroot; - loopi(3) solidfaces(c[i+1]); - worldroot = c; + worldscale++; + worldsize *= 2; + cube *c = newcubes(F_EMPTY); + c[0].children = worldroot; + loopi(3) solidfaces(c[i+1]); + worldroot = c; - if(worldsize > 0x1000) splitocta(worldroot, worldsize>>1); + if(worldsize > 0x1000) splitocta(worldroot, worldsize>>1); - enlargeblendmap(); + enlargeblendmap(); - allchanged(); + allchanged(); - return true; + return true; } static bool isallempty(cube &c) { - if(!c.children) return isempty(c); - loopi(8) if(!isallempty(c.children[i])) return false; - return true; + if(!c.children) return isempty(c); + loopi(8) if(!isallempty(c.children[i])) return false; + return true; } void shrinkmap() { - extern int nompedit; - if(noedit(true) || (nompedit && multiplayer())) return; - if(worldsize <= 1<<10) return; + extern int nompedit; + if(noedit(true) || (nompedit && multiplayer())) return; + if(worldsize <= 1<<10) return; - int octant = -1; - loopi(8) if(!isallempty(worldroot[i])) - { - if(octant >= 0) return; - octant = i; - } - if(octant < 0) return; + int octant = -1; + loopi(8) if(!isallempty(worldroot[i])) + { + if(octant >= 0) return; + octant = i; + } + if(octant < 0) return; - while(outsideents.length()) removeentity(outsideents.pop()); + while(outsideents.length()) removeentity(outsideents.pop()); - if(!worldroot[octant].children) subdividecube(worldroot[octant], false, false); - cube *root = worldroot[octant].children; - worldroot[octant].children = NULL; - freeocta(worldroot); - worldroot = root; - worldscale--; - worldsize /= 2; + if(!worldroot[octant].children) subdividecube(worldroot[octant], false, false); + cube *root = worldroot[octant].children; + worldroot[octant].children = NULL; + freeocta(worldroot); + worldroot = root; + worldscale--; + worldsize /= 2; - ivec offset(octant, ivec(0, 0, 0), worldsize); - vector<extentity *> &ents = entities::getents(); - loopv(ents) ents[i]->o.sub(vec(offset)); + ivec offset(octant, ivec(0, 0, 0), worldsize); + vector<extentity *> &ents = entities::getents(); + loopv(ents) ents[i]->o.sub(vec(offset)); - shrinkblendmap(octant); + shrinkblendmap(octant); - allchanged(); + allchanged(); - conoutf("shrunk map to size %d", worldscale); + conoutf("shrunk map to size %d", worldscale); } void newmap(int *i) { bool force = !isconnected(); if(force) game::forceedit(""); if(emptymap(*i, force, NULL)) game::newmap(max(*i, 0)); } @@ -1357,35 +1356,35 @@ COMMAND(shrinkmap, ""); void mapname() { - result(game::getclientmap()); + result(game::getclientmap()); } COMMAND(mapname, ""); void mpeditent(int i, const vec &o, int type, int attr1, int attr2, int attr3, int attr4, int attr5, bool local) { - if(i < 0 || i >= MAXENTS) return; - vector<extentity *> &ents = entities::getents(); - if(ents.length()<=i) - { - extentity *e = newentity(local, o, type, attr1, attr2, attr3, attr4, attr5, i); - if(!e) return; - addentity(i); - attachentity(*e); - } - else - { - extentity &e = *ents[i]; - removeentity(i); - int oldtype = e.type; - if(oldtype!=type) detachentity(e); - e.type = type; - e.o = o; - e.attr1 = attr1; e.attr2 = attr2; e.attr3 = attr3; e.attr4 = attr4; e.attr5 = attr5; - addentity(i); - if(oldtype!=type) attachentity(e); - } - entities::editent(i, local); + if(i < 0 || i >= MAXENTS) return; + vector<extentity *> &ents = entities::getents(); + if(ents.length()<=i) + { + extentity *e = newentity(local, o, type, attr1, attr2, attr3, attr4, attr5, i); + if(!e) return; + addentity(i); + attachentity(*e); + } + else + { + extentity &e = *ents[i]; + removeentity(i); + int oldtype = e.type; + if(oldtype!=type) detachentity(e); + e.type = type; + e.o = o; + e.attr1 = attr1; e.attr2 = attr2; e.attr3 = attr3; e.attr4 = attr4; e.attr5 = attr5; + addentity(i); + if(oldtype!=type) attachentity(e); + } + entities::editent(i, local); } int getworldsize() { return worldsize; } |
