added clip entities for easier clipping
added entset command for easier ent editing revised command completion system git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@3182 e016b1c5-ed68-44aa-a2f7-31cac88cffde
This commit is contained in:
@@ -1,3 +1,18 @@
|
||||
// standard completions
|
||||
|
||||
alias mapcomplete [complete $arg1 "packages/maps" cgz]
|
||||
|
||||
mapcommands = "map tdm coop dm lms ts ctf pf lss osok tosok htf vip tktf ktf"
|
||||
loop i (listlen $mapcommands) [
|
||||
mapcomplete (at $mapcommands $i)
|
||||
]
|
||||
|
||||
complete demo "demos" dmo
|
||||
|
||||
alias entcomplete [listcomplete $arg1 "light playerstart clips ammobox grenades health armour akimbo mapmodel trigger ladder ctf-flag sound clip"]
|
||||
|
||||
entcomplete newent
|
||||
|
||||
// standard menu definitions
|
||||
|
||||
newmenu main
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
alias editent [
|
||||
alias enttype (getenttype)
|
||||
if (! (strcmp enttype "")) [
|
||||
saycommand "/entset" $enttype (getentattr 0) (getentattr 1) (getentattr 2) (getentattr 3)
|
||||
]
|
||||
]
|
||||
|
||||
newmenu editing
|
||||
|
||||
menuitem "Mapmodels..." "showmenu Mapmodels"
|
||||
|
||||
@@ -40,7 +40,7 @@ bind 7 ""
|
||||
bind 8 "vdelta -1"
|
||||
bind 9 "vdelta 1"
|
||||
bind COLON ""
|
||||
bind SEMICOLON ""
|
||||
bind SEMICOLON "editent"
|
||||
bind LESS ""
|
||||
bind EQUALS ""
|
||||
bind GREATER ""
|
||||
|
||||
@@ -536,6 +536,7 @@ void parsemessages(int cn, playerent *d, ucharbuf &p)
|
||||
ents[i].attr4 = getint(p);
|
||||
ents[i].spawned = false;
|
||||
if(ents[i].type==LIGHT || to==LIGHT) calclight();
|
||||
if(ents[i].type==SOUND) preloadmapsound(ents[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+113
-24
@@ -440,14 +440,12 @@ int execute(const char *p)
|
||||
|
||||
// tab-completion of all idents
|
||||
|
||||
static int completesize = 0, completeidx = 0;
|
||||
static int completesize = -1, completeidx = 0;
|
||||
static playerent *completeplayer = NULL;
|
||||
static cvector maplist;
|
||||
static cvector newentlist;
|
||||
|
||||
void resetcomplete()
|
||||
{
|
||||
completesize = 0;
|
||||
completesize = -1;
|
||||
completeplayer = NULL;
|
||||
}
|
||||
|
||||
@@ -458,9 +456,9 @@ bool nickcomplete(char *s)
|
||||
if(!players.length()) return false;
|
||||
|
||||
char *cp = s;
|
||||
for(int i = (int)strlen(s) - 2; i > 0; i--)
|
||||
for(int i = (int)strlen(s) - 1; i > 0; i--)
|
||||
if(s[i] == ' ') { cp = s + i + 1; break; }
|
||||
if(!completesize) { completesize = (int)strlen(cp); completeidx = 0; }
|
||||
if(completesize < 0) { completesize = (int)strlen(cp); completeidx = 0; }
|
||||
|
||||
int idx = 0;
|
||||
if(completeplayer!=NULL)
|
||||
@@ -483,6 +481,86 @@ bool nickcomplete(char *s)
|
||||
return false;
|
||||
}
|
||||
|
||||
enum { COMPLETE_FILE = 0, COMPLETE_LIST, COMPLETE_NICK };
|
||||
|
||||
struct completekey
|
||||
{
|
||||
int type;
|
||||
const char *dir, *ext;
|
||||
|
||||
completekey() {}
|
||||
completekey(int type, const char *dir, const char *ext) : type(type), dir(dir), ext(ext) {}
|
||||
};
|
||||
|
||||
struct completeval
|
||||
{
|
||||
int type;
|
||||
char *dir, *ext;
|
||||
vector<char *> list;
|
||||
|
||||
completeval(int type, const char *dir, const char *ext) : type(type), dir(dir && dir[0] ? newstring(dir) : NULL), ext(ext && ext[0] ? newstring(ext) : NULL) {}
|
||||
~completeval() { DELETEA(dir); DELETEA(ext); list.deletecontentsa(); }
|
||||
};
|
||||
|
||||
static inline bool htcmp(const completekey &x, const completekey &y)
|
||||
{
|
||||
return x.type==y.type && (x.dir == y.dir || (x.dir && y.dir && !strcmp(x.dir, y.dir))) && (x.ext == y.ext || (x.ext && y.ext && !strcmp(x.ext, y.ext)));
|
||||
}
|
||||
|
||||
static inline uint hthash(const completekey &k)
|
||||
{
|
||||
return k.dir ? hthash(k.dir) + k.type : k.type;
|
||||
}
|
||||
|
||||
static hashtable<completekey, completeval *> completedata;
|
||||
static hashtable<char *, completeval *> completions;
|
||||
|
||||
void addcomplete(char *command, int type, char *dir, char *ext)
|
||||
{
|
||||
if(type==COMPLETE_FILE)
|
||||
{
|
||||
int dirlen = (int)strlen(dir);
|
||||
while(dirlen > 0 && (dir[dirlen-1] == '/' || dir[dirlen-1] == '\\'))
|
||||
dir[--dirlen] = '\0';
|
||||
if(ext)
|
||||
{
|
||||
if(strchr(ext, '*')) ext[0] = '\0';
|
||||
if(!ext[0]) ext = NULL;
|
||||
}
|
||||
}
|
||||
completekey key(type, dir, ext);
|
||||
completeval **val = completedata.access(key);
|
||||
if(!val)
|
||||
{
|
||||
completeval *f = new completeval(type, dir, ext);
|
||||
if(type==COMPLETE_LIST) explodelist(dir, f->list);
|
||||
val = &completedata[completekey(type, f->dir, f->ext)];
|
||||
*val = f;
|
||||
}
|
||||
completeval **hascomplete = completions.access(command);
|
||||
if(hascomplete) *hascomplete = *val;
|
||||
else completions[newstring(command)] = *val;
|
||||
}
|
||||
|
||||
void addfilecomplete(char *command, char *dir, char *ext)
|
||||
{
|
||||
addcomplete(command, COMPLETE_FILE, dir, ext);
|
||||
}
|
||||
|
||||
void addlistcomplete(char *command, char *list)
|
||||
{
|
||||
addcomplete(command, COMPLETE_LIST, list, NULL);
|
||||
}
|
||||
|
||||
void addnickcomplete(char *command)
|
||||
{
|
||||
addcomplete(command, COMPLETE_NICK, NULL, NULL);
|
||||
}
|
||||
|
||||
COMMANDN(complete, addfilecomplete, ARG_3STR);
|
||||
COMMANDN(listcomplete, addlistcomplete, ARG_2STR);
|
||||
COMMANDN(nickcomplete, addnickcomplete, ARG_1STR);
|
||||
|
||||
void commandcomplete(char *s)
|
||||
{
|
||||
if(*s!='/')
|
||||
@@ -494,23 +572,31 @@ void commandcomplete(char *s)
|
||||
}
|
||||
if(!s[1]) return;
|
||||
char *cp = s;
|
||||
for(int i = (int)strlen(s) - 2; i > 0; i--)
|
||||
for(int i = (int)strlen(s) - 1; i > 0; i--)
|
||||
if(s[i] == ';' || s[i] == ' ') { cp = s + i; break; }
|
||||
if(!completesize)
|
||||
bool init = false;
|
||||
if(completesize < 0)
|
||||
{
|
||||
completesize = (int)strlen(cp)-1;
|
||||
completeidx = 0;
|
||||
if(*cp == ' ')
|
||||
{
|
||||
maplist.setsize(0);
|
||||
listfiles("packages/maps", "cgz", maplist);
|
||||
if(!newentlist.length())
|
||||
{
|
||||
const char *neargs[] = { "light", "health", "armour", "akimbo", "grenades", "clips", "ammobox", "playerstart", "mapmodel", "ctf-flag", "ladder", "sound", "" };
|
||||
for(int i = 0; strlen(neargs[i]); i++) newentlist.add(newstring(neargs[i]));
|
||||
}
|
||||
}
|
||||
if(*cp == ' ') init = true;
|
||||
}
|
||||
|
||||
completeval *cdata = NULL;
|
||||
char *end = strchr(s, ' ');
|
||||
if(end && end <= cp)
|
||||
{
|
||||
string command;
|
||||
s_strncpy(command, s+1, min(size_t(end-s), sizeof(command)));
|
||||
completeval **hascomplete = completions.access(command);
|
||||
if(hascomplete) cdata = *hascomplete;
|
||||
}
|
||||
if(init && cdata && cdata->type==COMPLETE_FILE)
|
||||
{
|
||||
cdata->list.deletecontentsa();
|
||||
listfiles(cdata->dir, cdata->ext, cdata->list);
|
||||
}
|
||||
|
||||
if(*cp == '/' || *cp == ';')
|
||||
{ // commandname completion
|
||||
int idx = 0;
|
||||
@@ -524,20 +610,23 @@ void commandcomplete(char *s)
|
||||
completeidx++;
|
||||
if(completeidx>=idx) completeidx = 0;
|
||||
}
|
||||
else
|
||||
else if(!cdata) return;
|
||||
else if(cdata->type==COMPLETE_NICK) nickcomplete(s);
|
||||
else
|
||||
{ // argument completion
|
||||
cvector &list = strncmp(s, "/newent", 7) ? maplist : newentlist;
|
||||
loopv(list)
|
||||
loopv(cdata->list)
|
||||
{
|
||||
int j = (i + completeidx) % list.length();
|
||||
if(!_strncmpi(list[j], cp + 1, completesize))
|
||||
int j = (i + completeidx) % cdata->list.length();
|
||||
if(!_strncmpi(cdata->list[j], cp + 1, completesize))
|
||||
{
|
||||
cp[1] = '\0';
|
||||
s_strcat(s, list[j]);
|
||||
s_strcat(s, cdata->list[j]);
|
||||
completeidx = j + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
completeidx++;
|
||||
if(completeidx >= cdata->list.length()) completeidx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -481,7 +481,7 @@ void edittag(int tag)
|
||||
void newent(char *what, char *a1, char *a2, char *a3, char *a4)
|
||||
{
|
||||
EDITSEL;
|
||||
newentity(sel.x, sel.y, (int)camera1->o.z, what, ATOI(a1), ATOI(a2), ATOI(a3), ATOI(a4));
|
||||
newentity(-1, sel.x, sel.y, (int)camera1->o.z, what, ATOI(a1), ATOI(a2), ATOI(a3), ATOI(a4));
|
||||
}
|
||||
|
||||
COMMANDN(select, selectpos, ARG_4INT);
|
||||
|
||||
+39
-5
@@ -11,7 +11,8 @@ const char *entnames[] =
|
||||
"clips", "ammobox","grenades",
|
||||
"health", "armour", "akimbo",
|
||||
"mapmodel", "trigger",
|
||||
"ladder", "ctf-flag", "sound", "?", "?",
|
||||
"ladder", "ctf-flag",
|
||||
"sound", "clip", "", ""
|
||||
};
|
||||
|
||||
const char *entmdlnames[] =
|
||||
@@ -27,6 +28,34 @@ void renderent(entity &e)
|
||||
rendermodel(mdlname, ANIM_MAPMODEL|ANIM_LOOP|ANIM_DYNALLOC, 0, 0, vec(e.x, e.y, z+S(e.x, e.y)->floor+e.attr1), yaw, 0);
|
||||
}
|
||||
|
||||
void renderclip(entity &e)
|
||||
{
|
||||
float radius = max(float(e.attr2), 1.0f);
|
||||
vec bbmin(e.x - radius, e.y - radius, float(S(e.x, e.y)->floor+e.attr1)),
|
||||
bbmax(e.x + radius, e.y + radius, bbmin.z + max(float(e.attr3), 1.0f));
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
linestyle(1, 0xFF, 0xFF, 0);
|
||||
glBegin(GL_LINES);
|
||||
|
||||
glVertex3f(bbmin.x, bbmin.y, bbmin.z);
|
||||
loopi(2) glVertex3f(bbmax.x, bbmin.y, bbmin.z);
|
||||
loopi(2) glVertex3f(bbmax.x, bbmax.y, bbmin.z);
|
||||
loopi(2) glVertex3f(bbmin.x, bbmax.y, bbmin.z);
|
||||
glVertex3f(bbmin.x, bbmin.y, bbmin.z);
|
||||
|
||||
glVertex3f(bbmin.x, bbmin.y, bbmax.z);
|
||||
loopi(2) glVertex3f(bbmax.x, bbmin.y, bbmax.z);
|
||||
loopi(2) glVertex3f(bbmax.x, bbmax.y, bbmax.z);
|
||||
loopi(2) glVertex3f(bbmin.x, bbmax.y, bbmax.z);
|
||||
glVertex3f(bbmin.x, bbmin.y, bbmax.z);
|
||||
|
||||
loopi(8) glVertex3f(i&2 ? bbmax.x : bbmin.x, i&4 ? bbmax.y : bbmin.y, i&1 ? bbmax.z : bbmin.z);
|
||||
|
||||
glEnd();
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void renderentities()
|
||||
{
|
||||
if(editmode && !reflecting && !refracting && !stenciling)
|
||||
@@ -35,13 +64,14 @@ void renderentities()
|
||||
if(lastmillis - lastsparkle >= 20)
|
||||
{
|
||||
lastsparkle = lastmillis - (lastmillis%20);
|
||||
int closest = closestent();
|
||||
loopv(ents)
|
||||
{
|
||||
entity &e = ents[i];
|
||||
if(e.type==NOTUSED) continue;
|
||||
vec v(e.x, e.y, e.z);
|
||||
if(vec(v).sub(camera1->o).dot(camdir) < 0) continue;
|
||||
particle_splash(2, 2, 40, v);
|
||||
particle_splash(i == closest ? 12 : 2, 2, 40, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,10 +91,14 @@ void renderentities()
|
||||
renderent(e);
|
||||
}
|
||||
}
|
||||
else if(e.type==CTF_FLAG && editmode)
|
||||
else if(editmode)
|
||||
{
|
||||
s_sprintfd(path)("pickups/flags/%s", team_string(e.attr2));
|
||||
rendermodel(path, ANIM_FLAG|ANIM_LOOP, 0, 0, vec(e.x, e.y, (float)S(e.x, e.y)->floor), (float)((e.attr1+7)-(e.attr1+7)%15), 0, 120.0f);
|
||||
if(e.type==CTF_FLAG)
|
||||
{
|
||||
s_sprintfd(path)("pickups/flags/%s", team_string(e.attr2));
|
||||
rendermodel(path, ANIM_FLAG|ANIM_LOOP, 0, 0, vec(e.x, e.y, (float)S(e.x, e.y)->floor), (float)((e.attr1+7)-(e.attr1+7)%15), 0, 120.0f);
|
||||
}
|
||||
else if(e.type==CLIP) renderclip(e);
|
||||
}
|
||||
}
|
||||
if(m_flags) loopi(2)
|
||||
|
||||
+2
-1
@@ -3,13 +3,14 @@ enum // static entity types
|
||||
NOTUSED = 0, // entity slot not in use in map
|
||||
LIGHT, // lightsource, attr1 = radius, attr2 = intensity
|
||||
PLAYERSTART, // attr1 = angle, attr2 = team
|
||||
I_CLIPS, I_AMMO,I_GRENADE,
|
||||
I_CLIPS, I_AMMO, I_GRENADE,
|
||||
I_HEALTH, I_ARMOUR, I_AKIMBO,
|
||||
MAPMODEL, // attr1 = angle, attr2 = idx
|
||||
CARROT, // attr1 = tag, attr2 = type
|
||||
LADDER,
|
||||
CTF_FLAG, // attr1 = angle, attr2 = red/blue
|
||||
SOUND,
|
||||
CLIP,
|
||||
MAXENTTYPES
|
||||
};
|
||||
|
||||
|
||||
+24
-10
@@ -114,17 +114,31 @@ bool mmcollide(physent *d, float &hi, float &lo) // collide with a map
|
||||
loopv(ents)
|
||||
{
|
||||
entity &e = ents[i];
|
||||
if(e.type!=MAPMODEL) continue;
|
||||
mapmodelinfo &mmi = getmminfo(e.attr2);
|
||||
if(!&mmi || !mmi.h) continue;
|
||||
const float r = mmi.rad+d->radius;
|
||||
if(fabs(e.x-d->o.x)<r && fabs(e.y-d->o.y)<r)
|
||||
if(e.type==CLIP)
|
||||
{
|
||||
const float mmz = (float)(S(e.x, e.y)->floor+mmi.zoff+e.attr3);
|
||||
const float dz = d->o.z-eyeheight;
|
||||
if(dz<mmz) { if(mmz<hi) hi = mmz; }
|
||||
else if(mmz+mmi.h>lo) lo = mmz+mmi.h;
|
||||
if(hi-lo < playerheight) return false;
|
||||
const float r = max(float(e.attr2), 1.0f) + d->radius;
|
||||
if(fabs(e.x-d->o.x)<r && fabs(e.y-d->o.y)<r)
|
||||
{
|
||||
const float cz = float(S(e.x, e.y)->floor+e.attr1), ch = max(float(e.attr3), 1.0f);
|
||||
const float dz = d->o.z-d->eyeheight;
|
||||
if(dz<cz) { if(cz<hi) hi = cz; }
|
||||
else if(cz+ch>lo) lo = cz+ch;
|
||||
if(hi-lo < playerheight) return false;
|
||||
}
|
||||
}
|
||||
else if(e.type==MAPMODEL)
|
||||
{
|
||||
mapmodelinfo &mmi = getmminfo(e.attr2);
|
||||
if(!&mmi || !mmi.h) continue;
|
||||
const float r = mmi.rad+d->radius;
|
||||
if(fabs(e.x-d->o.x)<r && fabs(e.y-d->o.y)<r)
|
||||
{
|
||||
const float mmz = float(S(e.x, e.y)->floor+mmi.zoff+e.attr3);
|
||||
const float dz = d->o.z-eyeheight;
|
||||
if(dz<mmz) { if(mmz<hi) hi = mmz; }
|
||||
else if(mmz+mmi.h>lo) lo = mmz+mmi.h;
|
||||
if(hi-lo < playerheight) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
+1
-1
@@ -383,7 +383,7 @@ extern void remipmore(const block &b, int level = 0);
|
||||
extern int closestent();
|
||||
extern int findentity(int type, int index = 0);
|
||||
extern int findentity(int type, int index, uchar attr2);
|
||||
extern entity *newentity(int x, int y, int z, char *what, int v1, int v2, int v3, int v4);
|
||||
extern entity *newentity(int index, int x, int y, int z, char *what, int v1, int v2, int v3, int v4);
|
||||
|
||||
// worldlight
|
||||
extern int lastcalclight;
|
||||
|
||||
@@ -185,7 +185,7 @@ void cleanupexplosion()
|
||||
}
|
||||
}
|
||||
|
||||
#define MAXPARTYPES 12
|
||||
#define MAXPARTYPES 13
|
||||
|
||||
struct particle { vec o, d; int fade, type; int millis; particle *next; };
|
||||
particle *parlist[MAXPARTYPES], *parempty = NULL;
|
||||
@@ -263,6 +263,7 @@ static struct parttype { int type; float r, g, b; int gr, tex; float sz; } partt
|
||||
{ PT_DECAL, 1.0f, 1.0f, 1.0f, 0, 5, 1.5f }, // scorch decal
|
||||
{ PT_HUDFLASH, 1.0f, 1.0f, 1.0f, 0, 6, 0.7f }, // hudgun muzzle flash
|
||||
{ PT_FLASH, 1.0f, 1.0f, 1.0f, 0, 6, 0.7f }, // muzzle flash
|
||||
{ PT_PART, 1.0f, 0.5f, 0.2f, 20, 0, 0.08f }, // orange: edit mode closest ent
|
||||
};
|
||||
|
||||
VAR(particlesize, 20, 100, 500);
|
||||
|
||||
+57
-5
@@ -158,6 +158,31 @@ void entproperty(int prop, int amount)
|
||||
|
||||
hashtable<char *, enet_uint32> mapinfo, &resdata = mapinfo;
|
||||
|
||||
void getenttype()
|
||||
{
|
||||
int e = closestent();
|
||||
if(e<0) return;
|
||||
int type = ents[e].type;
|
||||
if(type < 0 || type >= MAXENTTYPES) return;
|
||||
result(entnames[type]);
|
||||
}
|
||||
|
||||
int getentattr(int attr)
|
||||
{
|
||||
int e = closestent();
|
||||
if(e>=0) switch(attr)
|
||||
{
|
||||
case 0: return ents[e].attr1;
|
||||
case 1: return ents[e].attr2;
|
||||
case 2: return ents[e].attr3;
|
||||
case 3: return ents[e].attr4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
COMMAND(getenttype, ARG_NONE);
|
||||
COMMAND(getentattr, ARG_1EXP);
|
||||
|
||||
void delent()
|
||||
{
|
||||
int e = closestent();
|
||||
@@ -179,7 +204,7 @@ int findtype(char *what)
|
||||
return NOTUSED;
|
||||
}
|
||||
|
||||
entity *newentity(int x, int y, int z, char *what, int v1, int v2, int v3, int v4)
|
||||
entity *newentity(int index, int x, int y, int z, char *what, int v1, int v2, int v3, int v4)
|
||||
{
|
||||
int type = findtype(what);
|
||||
if(type==NOTUSED) return NULL;
|
||||
@@ -188,8 +213,13 @@ entity *newentity(int x, int y, int z, char *what, int v1, int v2, int v3, int v
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case CLIP:
|
||||
if(v2<=0) e.attr2 = 1;
|
||||
if(v3<=0) e.attr3 = 1;
|
||||
break;
|
||||
|
||||
case LIGHT:
|
||||
if(v1>64) v1 = 64;
|
||||
if(v1>64) e.attr1 = 64;
|
||||
if(!v1) e.attr1 = 16;
|
||||
if(!v2 && !v3 && !v4) e.attr2 = 255;
|
||||
break;
|
||||
@@ -204,17 +234,39 @@ entity *newentity(int x, int y, int z, char *what, int v1, int v2, int v3, int v
|
||||
e.attr1 = (int)camera1->yaw;
|
||||
break;
|
||||
}
|
||||
addmsg(SV_EDITENT, "ri9", ents.length(), type, e.x, e.y, e.z, e.attr1, e.attr2, e.attr3, e.attr4);
|
||||
addmsg(SV_EDITENT, "ri9", index<0 ? ents.length() : index, type, e.x, e.y, e.z, e.attr1, e.attr2, e.attr3, e.attr4);
|
||||
e.spawned = true;
|
||||
ents.add(e);
|
||||
int oldtype = type;
|
||||
if(index<0) ents.add(e);
|
||||
else
|
||||
{
|
||||
oldtype = ents[index].type;
|
||||
ents[index] = e;
|
||||
}
|
||||
if(oldtype!=type) switch(oldtype)
|
||||
{
|
||||
case LIGHT: calclight(); break;
|
||||
}
|
||||
switch(type)
|
||||
{
|
||||
case LIGHT: calclight(); break;
|
||||
case SOUND: preloadmapsound(e); break;
|
||||
}
|
||||
return &ents.last();
|
||||
return index<0 ? &ents.last() : &ents[index];
|
||||
}
|
||||
|
||||
void entset(char *what, char *a1, char *a2, char *a3, char *a4)
|
||||
{
|
||||
int n = closestent();
|
||||
if(n>=0)
|
||||
{
|
||||
entity &e = ents[n];
|
||||
newentity(n, e.x, e.y, e.z, what, ATOI(a1), ATOI(a2), ATOI(a3), ATOI(a4));
|
||||
}
|
||||
}
|
||||
|
||||
COMMAND(entset, ARG_5STR);
|
||||
|
||||
void clearents(char *name)
|
||||
{
|
||||
int type = findtype(name);
|
||||
|
||||
Reference in New Issue
Block a user