model *loadmodel(const char *name, int i) { if(!name) { if(!mapmodels.inrange(i)) return NULL; mapmodelinfo &mmi = mapmodels[i]; if(mmi.m) return mmi.m; name = mmi.name; }; model **mm = mdllookup.access(name); model *m; if(mm) m = *mm; else { m = new md2(name); loadingmodel = m; if(!m->load()) { delete m; m = new md3(name); loadingmodel = m; if(!m->load()) { delete m; loadingmodel = NULL; return NULL; }; }; loadingmodel = NULL; mdllookup.access(m->name(), &m); }; if(mapmodels.inrange(i) && !mapmodels[i].m) mapmodels[i].m = m; return m; };
void freechannel(int n) { if(!channels.inrange(n) || !channels[n].inuse) return; soundchannel &chan = channels[n]; chan.inuse = false; if(chan.ent) chan.ent->flags &= ~EF_SOUND; }
bool getdynlight(int n, vec &o, float &radius, vec &color) { if(!closedynlights.inrange(n)) return false; dynlight &d = *closedynlights[n]; o = d.o; radius = d.curradius; color = d.curcolor; return true; }
void freechannel(int n) { // Note that this can potentially be called from the SDL_mixer audio thread. // Be careful of race conditions when checking chan.inuse without locking audio. // Can't use Mix_Playing() checks due to bug with looping sounds in SDL_mixer. if(!channels.inrange(n) || !channels[n].inuse) return; soundchannel &chan = channels[n]; chan.inuse = false; if(chan.ent) chan.ent->visible = false; }
soundchannel &newchannel(int n, soundsample *sample, int volume, const vec *loc = NULL, extentity *ent = NULL, int flags = 0, int radius = 0) { if(ent) ent->flags |= EF_SOUND; while(!channels.inrange(n)) channels.add(channels.length()); soundchannel &chan = channels[n]; chan.reset(); chan.inuse = true; if(loc) chan.loc = *loc; chan.sample = sample; chan.ent = ent; chan.svolume = volume; chan.flags = 0; chan.radius = radius; return chan; }
soundchannel &newchannel(int n, soundslot *slot, const vec *loc = NULL, extentity *ent = NULL, int radius = 0) { if(ent) { loc = &ent->o; ent->visible = true; } while(!channels.inrange(n)) channels.add(channels.length()); soundchannel &chan = channels[n]; chan.reset(); chan.inuse = true; if(loc) chan.loc = *loc; chan.slot = slot; chan.ent = ent; chan.radius = radius; return chan; }
const char *mapmodelname(int i) { return mapmodels.inrange(i) ? mapmodels[i].name : NULL; }
mapmodelinfo *getmminfo(int i) { return mapmodels.inrange(i) ? &mapmodels[i] : 0; }
mmodel(name); } void mapmodelreset(int *n) { if(!(identflags&IDF_OVERRIDDEN) && !game::allowedittoggle()) return; mapmodels.shrink(clamp(*n, 0, mapmodels.length())); } mapmodelinfo *getmminfo(int i) { return mapmodels.inrange(i) ? &mapmodels[i] : 0; } const char *mapmodelname(int i) { return mapmodels.inrange(i) ? mapmodels[i].name : NULL; } COMMAND(mmodel, "s"); COMMANDN(mapmodel, mapmodelcompat, "iiiss"); COMMAND(mapmodelreset, "i"); ICOMMAND(mapmodelname, "i", (int *index), { result(mapmodels.inrange(*index) ? mapmodels[*index].name : ""); }); ICOMMAND(nummapmodels, "", (), { intret(mapmodels.length()); }); // model registry hashtable<const char *, model *> mdllookup; vector<const char *> preloadmodels; void preloadmodel(const char *name) { if(!name || !name[0] || mdllookup.access(name)) return; preloadmodels.add(newstring(name)); } void flushpreloadedmodels(bool msg) {
mapmodelinfo &getmminfo(int i) { return mapmodels.inrange(i) ? mapmodels[i] : *(mapmodelinfo *)0; }
const char *getclienthostname(int n) { return clients.inrange(n) ? clients[n]->hostname : ""; }
uint getclientip(int n) { return clients.inrange(n) && clients[n]->type==ST_TCPIP ? clients[n]->peer->address.host : 0; }
ENetPeer *getclientpeer(int i) { return clients.inrange(i) && clients[i]->type==ST_TCPIP ? clients[i]->peer : NULL; }
void *getclientinfo(int i) { return !clients.inrange(i) || clients[i]->type==ST_EMPTY ? NULL : clients[i]->info; }