From 8745d002f00e386e4c59a47a611ea36c74ccb940 Mon Sep 17 00:00:00 2001 From: ac-stef Date: Tue, 28 Apr 2015 01:58:01 +0200 Subject: [PATCH] new commands to edit map config items automapconfig Enables the "automatic embedded map config data" feature, which means with the next map save the map config file gets renamed and the map config data stored inside the map file. mapsoundslotusage Returns a list of map entity indices which use a certain map sound slot. If the sound is unused, it returns an empty string. deletemapsoundslot <"purge"> Deletes an unused map sound slot. If "purge" is specified as second argument, it also deletes an used slot (including all map entities which use that sound). Also enables automapconfig. editmapsoundslot Edits path/name and maxuses parameters of a mapsound slot. Only non-empty parameters actually change something. The command returns the resulting data of the map sound slot. If only the map sound slot number is specified, no changes are made, but the current data is returned. Therefore the command can be used to get and set parameters. If anything is changed, automapconfig is enabled. mapmodelslotusage Returns a list of map entity indices which use a certain mapmodel slot. If the mapmodel is unused, it returns an empty string. deletemapmodelslot <"purge"> Deletes an unused mapmodel slot. If "purge" is specified as second argument, it also deletes an used slot (including all map entities which use that mapmodel). Also enables automapconfig. editmapmodelslot 0 Edits the parameters of a mapmodel slot. Only non-empty parameters actually change something. The command returns the resulting data of the mapmodel slot. If only the mapmodel slot number is specified, no changes are made, but the current data is returned. Therefore the command can be used to get and set parameters. examples: editmapmodelslot 33 "" "" -5 sets the z-offset of slot #33 to -5 without affecting other params echo (editmapmodelslot 33) print the current parameters of mapmodel slot #33 for example: 0 0 0 0 "makke/lightbulb" If anything is changed, automapconfig is enabled. gettexturelist Returns a table of all texture files fitting a certain description. includes Optional list of path prefixes to include in the table. excludes Optional list of path prefixes to exclude from the table. extensions Optional list of filename extensions to include in the table. All files found under packages/textures are examined. By default, the command returns a list with two columns: path and filename. If "excludes" is exactly one path prefix to exclude, the table gets a third column with path names without that prefix. If "extensions" is exactly one extension which does not start with the character '.', the table gets an additional (third or fourth) column containing file names without that extension. examples: echo (gettexturelist) outputs two columns like "noctua/wall" "wall02.jpg" echo (gettexturelist "" "map_editor skymaps") same, but omits skymaps and special textures for the editor echo (gettexturelist makke) outputs only textures by makke and adds a third column like "makke/rattrap" "rb_box_03.jpg" "/rattrap" echo (gettexturelist "skymaps/" "" "_ft.jpg") outputs four columns like "skymaps/egypt" "egypt_ft.jpg" "egypt" "egypt" "skymaps/humus" "meadow_ft.jpg" "humus" "meadow" textureslotusage Returns a list of mapmodels who use that texture as skin. If no mapmodel uses the texture, but world geometry does, a string of whitespace is returned. If the mapmodel is unused, an empty string is returned. deletetextureslot <"purge"> Deletes an unused texture slot. If "purge" is specified as second argument, it also deletes an used slot. All mapmodels that use that texture as skin are changed to default skin. All world geometry, which uses the texture, is instead set to use slot #255. Slots below #5 always require "purge", no matter if they are in use (default slots). Also enables automapconfig. edittextureslot Edits the parameters of a texture slot. Only non-empty parameters actually change something. The command returns the resulting data of the texture slot. If only the texture slot number is specified, no changes are made, but the current data is returned. Therefore the command can be used to get and set parameters. examples: edittextureslot 33 "" "arcitool/rohbaubims.jpg" sets texture name of slot #33 echo (edittextureslot 33) print the current parameters of texture slot #33 for example: 0 "zastrow/3wood_crate_10.jpg" If anything is changed, automapconfig is enabled. deleteentity Deletes a map entity. (Note: deleting an entity only marks it as unused. It will be completely removed after saving and loading the map.) editentity Edits a map entity. Edits only parameters given a non-empty value. Returns the values of all attributes (type, x, y, z, attr1-attr4). examples: echo (editentity 33) prints all attributes of map entity number 33 for example "light 174 172 12 20 255 200 200" editentity 33 "" 173 changes the y-position of entity 33 to 173 rereadtexturelists Variable, which is set to "1" when a texture is downloaded. Used to trigger menu rebuilds. rereadsoundlists Variable, which is set to "1" when a sound is downloaded. Used to trigger menu rebuilds. DOCREF mapsoundslotusage deletemapsoundslot editmapsoundslot DOCREF mapmodelslotusage deletemapmodelslot editmapmodelslot DOCREF textureslotusage deletetextureslot edittextureslot DOCREF gettexturelist deleteentity editentity DOCREF automapconfig rereadtexturelists rereadsoundlists --- source/src/audiomanager.cpp | 67 ++++++++++++ source/src/client.cpp | 6 ++ source/src/protos.h | 1 + source/src/rendermodel.cpp | 57 ++++++++++ source/src/texture.cpp | 200 +++++++++++++++++++++++++++++++----- source/src/world.cpp | 80 +++++++++++++-- source/src/worldio.cpp | 7 ++ 7 files changed, 388 insertions(+), 30 deletions(-) diff --git a/source/src/audiomanager.cpp b/source/src/audiomanager.cpp index 98a641c0..7377cdea 100644 --- a/source/src/audiomanager.cpp +++ b/source/src/audiomanager.cpp @@ -835,3 +835,70 @@ COMMANDF(music, "sis", (char *name, int *millis, char *cmd) audiomgr.music(name, *millis, cmd); }); +void mapsoundslotusage(int *n) // returns all entity indices that use a mapsound of slot n +{ + string res = ""; + loopv(ents) if(ents[i].type == SOUND && ents[i].attr1 == *n) concatformatstring(res, "%s%d", i ? " " : "", i); + result(res); +} +COMMAND(mapsoundslotusage, "i"); + +void reloadmapsoundconfig() +{ + vector sc; + getcurrentmapconfig(sc, true); // only soundconfig + sc.add('\0'); + execute(sc.getbuf()); // cheap and easy way ;) +} + +void deletemapsoundslot(int *n, char *opt) // delete mapsound slot - only if unused or "purge" is specified +{ + if(noteditmode("deletemapsoundslot") || multiplayer(true) || !mapconfigdata.mapsoundlines.inrange(*n)) return; + bool purgeall = !strcmp(opt, "purge"), slotused = false; + loopv(ents) if(ents[i].type == SOUND && ents[i].attr1 == *n) slotused = true; + if(!purgeall && slotused) { conoutf("mapsound slot #%d is in use: can't delete", *n); return; } + audiomgr.mapsoundreset(); + int deld = 0; + loopv(ents) if(ents[i].type == SOUND) + { + entity &e = ents[i]; + if(e.attr1 == *n) + { // delete entity + deletesoundentity(e); + memset(&e, 0, sizeof(persistent_entity)); + e.type = NOTUSED; + deld++; + } + else if(e.attr1 > *n) e.attr1--; // adjust models in higher slots + } + mapconfigdata.mapsoundlines.remove(*n); + reloadmapsoundconfig(); + defformatstring(s)(" (%d mapsounds purged)", deld); + conoutf("mapsound slot #%d deleted%s", *n, deld ? s : ""); + mapsoundchanged = 1; + unsavededits++; + hdr.flags |= MHF_AUTOMAPCONFIG; // requires automapcfg +} +COMMAND(deletemapsoundslot, "is"); + +void editmapsoundslot(int *n, char *name, char *maxuses) // edit slot parameters != "" +{ + string res = ""; + if(!noteditmode("editmapsoundslot") && !multiplayer(true) && mapconfigdata.mapsoundlines.inrange(*n)) + { + mapsoundline &msl = mapconfigdata.mapsoundlines[*n]; + if(*name || *maxuses) + { // change attributes + if(*maxuses) msl.maxuses = strtol(maxuses, NULL, 0); + if(*name) copystring(msl.name, name); + reloadmapsoundconfig(); + mapsoundchanged = 1; + unsavededits++; + hdr.flags |= MHF_AUTOMAPCONFIG; // requires automapcfg + } + formatstring(res)("\"%s\" %d", msl.name, msl.maxuses); // give back all current attributes + } + result(res); +} +COMMAND(editmapsoundslot, "isssss"); + diff --git a/source/src/client.cpp b/source/src/client.cpp index f7a790b8..a17ebb4c 100644 --- a/source/src/client.cpp +++ b/source/src/client.cpp @@ -1010,6 +1010,9 @@ int progress_callback_dlpackage(void *clientp, double dltotal, double dlnow, dou return 0; } +VAR(rereadtexturelists, 0, 1, 1); // flag to indicate additional texture files to trigger a menu rebuild (defaults to "1" to build the menus after startup) +VAR(rereadsoundlists, 0, 1, 1); // same for map sounds + int processdownload(package *pck) { string tmpname = ""; @@ -1023,6 +1026,8 @@ int processdownload(package *pck) const char *pckname = findfile(path(pck->name, true), "w+"); // with textures/sounds, the image/audio file itself is sent. Just need to copy it from the temporary file if(rename(tmpname, pckname)) conoutf(_("\f3failed to install"), pckname); + if(pck->type == PCK_TEXTURE) rereadtexturelists = 1; + else rereadsoundlists = 1; break; } @@ -1037,6 +1042,7 @@ int processdownload(package *pck) char *fname = newstring(pck->name), *ls = strrchr(fname, '/'); if(ls) *ls = '\0'; addzip(tmpname, fname, NULL, true, pck->type); + rereadtexturelists = 1; break; } diff --git a/source/src/protos.h b/source/src/protos.h index d61a3490..ead6f6b3 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -485,6 +485,7 @@ extern bool empty_world(int factor, bool force); extern void remip(const block &b, int level = 0); extern void remipmore(const block &b, int level = 0); extern int closestent(); +extern void deletesoundentity(entity &e); extern int findtype(char *what); extern int findentity(int type, int index = 0); extern int findentity(int type, int index, uchar attr2); diff --git a/source/src/rendermodel.cpp b/source/src/rendermodel.cpp index 24d23b96..f943018d 100644 --- a/source/src/rendermodel.cpp +++ b/source/src/rendermodel.cpp @@ -148,6 +148,63 @@ COMMANDF(mapmodelslotbyname, "s", (char *name) // returns the slot(s) that a cer result(res); }); +void mapmodelslotusage(int *n) // returns all entity indices that contain a mapmodel of slot n +{ + string res = ""; + loopv(ents) if(ents[i].type == MAPMODEL && ents[i].attr2 == *n) concatformatstring(res, "%s%d", i ? " " : "", i); + result(res); +} +COMMAND(mapmodelslotusage, "i"); + +void deletemapmodelslot(int *n, char *opt) // delete mapmodel slot - only if unused or "purge" is specified +{ + if(noteditmode("deletemapmodelslot") || multiplayer(true) || !mapmodels.inrange(*n)) return; + bool purgeall = !strcmp(opt, "purge"); + if(!purgeall) loopv(ents) if(ents[i].type == MAPMODEL && ents[i].attr2 == *n) { conoutf("mapmodel slot #%d is in use: can't delete", *n); return; } + int deld = 0; + loopv(ents) if(ents[i].type == MAPMODEL) + { + entity &e = ents[i]; + if(e.attr2 == *n) + { // delete entity + memset(&e, 0, sizeof(persistent_entity)); + e.type = NOTUSED; + deld++; + } + else if(e.attr2 > *n) e.attr2--; // adjust models in higher slots + } + mapmodels.remove(*n); + defformatstring(s)(" (%d mapmodels purged)", deld); + conoutf("mapmodel slot #%d deleted%s", *n, deld ? s : ""); + unsavededits++; + mapmodelchanged = 1; + hdr.flags |= MHF_AUTOMAPCONFIG; // requires automapcfg +} +COMMAND(deletemapmodelslot, "is"); + +void editmapmodelslot(int *n, char *rad, char *h, char *zoff, char *snap, char *name) // edit slot parameters != "" +{ + string res = ""; + if(!noteditmode("editmapmodelslot") && !multiplayer(true) && mapmodels.inrange(*n)) + { + mapmodelinfo &mmi = mapmodels[*n]; + if(*rad || *h || *zoff || *snap || *name) + { // change attributes + if(*rad) mmi.rad = strtol(rad, NULL, 0); + if(*h) mmi.h = strtol(h, NULL, 0); + if(*zoff) mmi.zoff = strtol(zoff, NULL, 0); + mmi.m = NULL; + if(*name) formatstring(mmi.name)("%s%s", mmpath, name); + unsavededits++; + mapmodelchanged = 1; + hdr.flags |= MHF_AUTOMAPCONFIG; // requires automapcfg + } + formatstring(res)("%d %d %d 0 \"%s\"", mmi.rad, mmi.h, mmi.zoff, mmshortname(mmi.name)); // give back all current attributes + } + result(res); +} +COMMAND(editmapmodelslot, "isssss"); + hashtable mdlregistry; void setmodelattributes(const char *name, mapmodelattributes &ma) diff --git a/source/src/texture.cpp b/source/src/texture.cpp index 5c088c21..420697e2 100644 --- a/source/src/texture.cpp +++ b/source/src/texture.cpp @@ -497,35 +497,44 @@ COMMANDF(texturereset, "", () } }); -void texture(float *scale, char *name) +void _texture(Slot &s, float *scale, char *name) +{ + if(name) + { + filtertext(s.name, parentdir(name), FTXT__MEDIAFILEPATH); // filter parts separately, because filename may (legally) contain "" + if(*s.name) concatstring(s.name, "/"); + name = (char *)behindpath(name); + if(*name == '<') + { + char *endcmd = strchr(name, '>'); + if(endcmd) + { + *endcmd = '\0'; + concatstring(s.name, name); + concatstring(s.name, ">"); + name = endcmd + 1; + } + } + filtertext(name, name, FTXT__MEDIAFILENAME); + concatstring(s.name, name); + } + s.tex = NULL; + s.loaded = false; + if(scale) + { + s.orgscale = *scale; + s.scale = (*scale > 0 && *scale <= 2.0f) ? *scale : 1.0f; + } +} + +COMMANDF(texture, "fs", (float *scale, char *name) { intret(slots.length()); Slot &s = slots.add(); - filtertext(s.name, parentdir(name), FTXT__MEDIAFILEPATH); // filter parts separately, because filename may (legally) contain "" - if(*s.name) concatstring(s.name, "/"); - name = (char *)behindpath(name); - if(*name == '<') - { - char *endcmd = strchr(name, '>'); - if(endcmd) - { - *endcmd = '\0'; - concatstring(s.name, name); - concatstring(s.name, ">"); - name = endcmd + 1; - } - } - filtertext(name, name, FTXT__MEDIAFILENAME); - concatstring(s.name, name); - - s.tex = NULL; - s.loaded = false; - s.orgscale = *scale; - s.scale = (*scale > 0 && *scale <= 2.0f) ? *scale : 1.0f; + _texture(s, scale, name); flagmapconfigchange(); -} +}); -COMMAND(texture, "fs"); const char *gettextureslot(int i) { @@ -926,3 +935,146 @@ void guidetoggle() } COMMAND(guidetoggle, ""); + +void gettexturelist(char *_filter, char *_exclude, char *_exts) // create a list of texture paths and filenames +{ + vector filter, exclude, exts, files; + vector filter_n, exclude_n, exts_n; + explodelist(_filter, filter); // path has to start with one of these + explodelist(_exclude, exclude); // path may not start with one of these + explodelist(_exts, exts); // file needs to have one of those extensions (or ".jpg" by default) + if(!exts.length()) exts.add(newstring(".jpg")); + loopv(filter) filter_n.add((int) strlen(filter[i])); + loopv(exclude) exclude_n.add((int) strlen(exclude[i])); + loopv(exts) exts_n.add((int) strlen(exts[i])); + listfilesrecursive("packages/textures", files); + files.sort(stringsort); + loopvrev(files) if(files.inrange(i + 1) && !strcmp(files[i], files[i + 1])) delstring(files.remove(i + 1)); // remove doubles + int pn = strlen("packages/textures/"); + loopvrev(files) + { + bool filtered = filter.length() == 0, excluded = false, extmatch = false; + if(!strncmp(files[i], "packages/textures/", pn)) + { + const char *s = files[i] + pn; + loopvj(filter) if(!strncmp(s, filter[j], filter_n[j])) filtered = true; + loopvj(exclude) if(!strncmp(s, exclude[j], exclude_n[j])) excluded = true; + int n = strlen(s); + loopvj(exts) if(n > exts_n[j] && !strcmp(s + n - exts_n[j], exts[j])) extmatch = true; + } + if(!extmatch || !filtered || excluded) delstring(files.remove(i)); + } + vector res; + bool cutprefix = filter.length() == 1; + bool cutext = exts.length() == 1 && exts[0][0] != '.'; + loopv(files) + { + char *f = files[i] += pn; + const char *p = parentdir(f), *b = behindpath(f); + cvecprintf(res, "\"%s\" \"%s\"", p, b); // always add columns for path (without "packages/textures/") and filename + if(cutprefix) cvecprintf(res, " \"%s\"", int(strlen(p)) > filter_n[0] ? p + filter_n[0] : ""); // if there's exactly one filter string, add column with that string omitted + if(cutext) + { + int n = strlen(b); + if(n > exts_n[0]) ((char *)b)[n - exts_n[0]] = '\0'; + cvecprintf(res, " \"%s\"", b); // if there's only one allowed extension and it does not start with '.', add column of filenames without extension + } + res.add('\n'); + } + if(res.length()) res.last() = '\0'; + else res.add('\0'); + filter.deletearrays(); + exclude.deletearrays(); + exts.deletearrays(); + result(res.getbuf()); +} +COMMAND(gettexturelist, "sss"); + +bool testworldtexusage(int n) +{ + sqr *s = world; + loopirev(cubicsize) + { + if(s->wtex == n || s->ctex == n || s->ftex == n || s->utex == n) return true; + s++; + } + return false; +} + +void textureslotusage(int *n) // returns all mapmodel entity indices that use a certain texture to skin the model + // if the texture is used in map geometry, at least a space is returned + // if the texture is unused, an empty string is returned +{ + string res = ""; + loopv(ents) if(ents[i].type == MAPMODEL && ents[i].attr4 == *n) concatformatstring(res, "%s%d", i ? " " : "", i); + if(!*res) + { // not used to skin a mapmodel: check world usage... + if(testworldtexusage(*n)) copystring(res, " "); + } + result(res); +} +COMMAND(textureslotusage, "i"); + +void deletetextureslot(int *n, char *opt) // delete texture slot - only if unused or "purge" is specified +{ + if(noteditmode("deletetextureslot") || multiplayer(true) || !slots.inrange(*n)) return; + bool purgeall = !strcmp(opt, "purge"); + bool mmused = false; + loopv(ents) if(ents[i].type == MAPMODEL && ents[i].attr4 == *n) mmused = true; + if(!purgeall && *n <= DEFAULT_CEIL) { conoutf("texture slots below #%d should usually not be deleted", DEFAULT_CEIL + 1); return; } + if(!purgeall && (mmused || testworldtexusage(*n))) { conoutf("texture slot #%d is in use: can't delete", *n); return; } + int deld = 0; + sqr *s = world; + loopirev(cubicsize) + { // check, if cubes use the texture + if(s->wtex == *n) { s->wtex = 255; deld++; } + else if(s->wtex > *n) s->wtex--; + if(s->ctex == *n) { s->ctex = 255; deld++; } + else if(s->ctex > *n) s->ctex--; + if(s->ftex == *n) { s->ftex = 255; deld++; } + else if(s->ftex > *n) s->ftex--; + if(s->utex == *n) { s->utex = 255; deld++; } + else if(s->utex > *n) s->utex--; + s++; + } + block bb = { mapdims.x1 - 1, mapdims.y1 - 1, mapdims.xspan + 2, mapdims.yspan + 2 }; + remip(bb); + loopv(ents) if(ents[i].type == MAPMODEL) + { // check, if mapmodels use the texture + entity &e = ents[i]; + if(e.attr4 == *n) + { // use default model texture instead + e.attr4 = 0; + deld++; + } + else if(e.attr4 > *n) e.attr4--; // adjust models in higher slots + } + // FIXME: texlists... + slots.remove(*n); + defformatstring(m)(" (%d uses removed)", deld); + conoutf("texture slot #%d deleted%s", *n, deld ? m : ""); + unsavededits++; + hdr.flags |= MHF_AUTOMAPCONFIG; // requires automapcfg +} +COMMAND(deletetextureslot, "is"); + +void edittextureslot(int *n, char *scale, char *name) // edit slot parameters != "" +{ + string res = ""; + if(!noteditmode("edittextureslot") && !multiplayer(true) && slots.inrange(*n)) + { + Slot &s = slots[*n]; + if(*scale || *name) + { // change attributes + float newscale = atof(scale); + _texture(s, *scale ? &newscale : NULL, *name ? name : NULL); + unsavededits++; + hdr.flags |= MHF_AUTOMAPCONFIG; // requires automapcfg + } + defformatstring(d)("%d", int(s.orgscale)); + formatstring(res)("%s \"%s\"", s.orgscale == int(s.orgscale) ? d : floatstr(s.orgscale), s.name); + } + result(res); +} +COMMAND(edittextureslot, "iss"); + diff --git a/source/src/world.cpp b/source/src/world.cpp index d4a22a28..cf26eded 100644 --- a/source/src/world.cpp +++ b/source/src/world.cpp @@ -171,6 +171,7 @@ void entproperty(int prop, int amount) int n = closestent(); if(n<0) return; entity &e = ents[n]; + int old_a1 = e.attr1; switch(prop) { case 0: e.attr1 += amount; break; @@ -187,7 +188,7 @@ void entproperty(int prop, int amount) case SOUND: audiomgr.preloadmapsound(e); entityreference entref(&e); - location *loc = audiomgr.locations.find(e.attr1-amount, &entref, mapsounds); + location *loc = audiomgr.locations.find(old_a1, &entref, mapsounds); if(loc) loc->drop(); } @@ -222,6 +223,13 @@ void getentattr(int *attr) COMMAND(getenttype, ""); COMMAND(getentattr, "i"); +void deletesoundentity(entity &e) +{ + entityreference entref(&e); + location *loc = audiomgr.locations.find(e.attr1, &entref, mapsounds); + if(loc) loc->drop(); +} + void delent() { int n = closestent(); @@ -234,11 +242,7 @@ void delent() if (t == SOUND) //stop playing sound { - entityreference entref(&e); - location *loc = audiomgr.locations.find(e.attr1, &entref, mapsounds); - - if(loc) - loc->drop(); + deletesoundentity(e); } ents[n].type = NOTUSED; @@ -348,6 +352,70 @@ void clearents(char *name) COMMAND(clearents, "s"); +// entity commands based on entity number (for scripts, singleplayer only) + +void deleteentity(char *ns) +{ + int n = ATOI(ns); + if(noteditmode("deleteentity") || multiplayer(true) || !*ns || !ents.inrange(n)) return; + entity &e = ents[n]; + int t = e.type; + if(t == SOUND) deletesoundentity(e); + conoutf("deleted entity #%d (%s)", n, entnames[e.type]); + memset(&e, 0, sizeof(persistent_entity)); + e.type = NOTUSED; + if(t == LIGHT) calclight(); + unsavededits++; +} +COMMAND(deleteentity, "s"); + +void editentity(char **args, int numargs) // index x y z a1 a2 a3 a4 ... +{ + string res = ""; + if(numargs > 0) + { + int n = ATOI(args[0]); + if(noteditmode("editentity") || multiplayer(true) || !*args[0] || !ents.inrange(n)) return; + entity &e = ents[n]; + bool edit = false; + for(int i = 1; i < numargs; i++) if(*args[i]) edit = true; // only arguments other than empty strings can edit anything - otherwise we're just browsing + if(edit) + { + if(e.type == SOUND) + { // disable sound /before/ changing it + entityreference entref(&e); + location *loc = audiomgr.locations.find(e.attr1, &entref, mapsounds); + if(loc) loc->drop(); + } + for(int i = 1; i < numargs; i++) if(*args[i]) + { + int v = ATOI(args[i]); + switch(i) + { + case 1: e.x = v; break; + case 2: e.y = v; break; + case 3: e.z = v; break; + case 4: e.attr1 = v; break; + case 5: e.attr2 = v; break; + case 6: e.attr3 = v; break; + case 7: e.attr4 = v; break; + } + } + switch(e.type) + { + case LIGHT: calclight(); break; + case SOUND: audiomgr.preloadmapsound(e); break; + } + unsavededits++; + } + // give back unchanged or new entity properties + formatstring(res)("%s %d %d %d %d %d %d %d", entnames[e.type], e.x, e.y, e.z, e.attr1, e.attr2, e.attr3, e.attr4); + } + result(res); +} +COMMAND(editentity, "v"); + + void scalecomp(uchar &c, int intens) { int n = c*intens/100; diff --git a/source/src/worldio.cpp b/source/src/worldio.cpp index 6b005422..c1867c41 100644 --- a/source/src/worldio.cpp +++ b/source/src/worldio.cpp @@ -395,6 +395,13 @@ void extractconfigfile() } COMMAND(extractconfigfile, ""); +void automapconfig() +{ + conoutf("\"automatic embedded map config data\" %senabled", hdr.flags & MHF_AUTOMAPCONFIG ? "was already " : ""); + hdr.flags |= MHF_AUTOMAPCONFIG; +} +COMMAND(automapconfig, ""); + void flagmapconfigchange() { if(hdr.flags & MHF_AUTOMAPCONFIG) unsavededits++;