~ubuntu-branches/debian/stretch/assaultcube-data/stretch

« back to all changes in this revision

Viewing changes to source/src/editing.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Gonéri Le Bouder, Ansgar Burchardt, Gonéri Le Bouder
  • Date: 2010-04-02 23:37:55 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100402233755-kf74fxwlu634o6vg
Tags: 1.0.4+repack1-1
[ Ansgar Burchardt ]
* debian/control: fix typo in short description

[ Gonéri Le Bouder ]
* Upgrade to 1.0.4
* bump standards-version to 3.8.4
* Add Depends: ${misc:Depends} just to avoid a lintian warning
* Add a debian/source/format file for the same reason

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// editing.cpp: most map editing commands go here, entity editing commands are in world.cpp
 
2
 
 
3
#include "pch.h"
 
4
#include "cube.h"
 
5
 
 
6
bool editmode = false;
 
7
 
 
8
// the current selection, used by almost all editing commands
 
9
// invariant: all code assumes that these are kept inside MINBORD distance of the edge of the map
 
10
 
 
11
block sel =
 
12
{
 
13
    variable("selx",  0, 0, 4096, &sel.x,  NULL, false),
 
14
    variable("sely",  0, 0, 4096, &sel.y,  NULL, false),
 
15
    variable("selxs", 0, 0, 4096, &sel.xs, NULL, false),
 
16
    variable("selys", 0, 0, 4096, &sel.ys, NULL, false),
 
17
};
 
18
 
 
19
int selh = 0;
 
20
bool selset = false;
 
21
 
 
22
#define loopselxy(b) { makeundo(); loop(x,sel.xs) loop(y,sel.ys) { sqr *s = S(sel.x+x, sel.y+y); b; } remip(sel); }
 
23
 
 
24
int cx, cy, ch;
 
25
 
 
26
int curedittex[] = { -1, -1, -1 };
 
27
 
 
28
bool dragging = false;
 
29
int lastx, lasty, lasth;
 
30
 
 
31
int lasttype = 0, lasttex = 0;
 
32
sqr rtex;
 
33
 
 
34
VAR(editing, 1, 0, 0);
 
35
 
 
36
void toggleedit(bool force)
 
37
{
 
38
    if(player1->state==CS_DEAD) return;                   // do not allow dead players to edit to avoid state confusion
 
39
    if(!force && !editmode && !allowedittoggle()) return; // not in most multiplayer modes
 
40
    if(!(editmode = !editmode))
 
41
    {
 
42
        entinmap(player1);                                // find spawn closest to current floating pos
 
43
    }
 
44
    else
 
45
    {
 
46
        //player1->health = 100; // illusion only (client-side) and unwanted anyway (bug found by grenadier)
 
47
        //put call to clear/restart gamemode
 
48
                player1->attacking = false;
 
49
    }
 
50
    keyrepeat(editmode);
 
51
    selset = false;
 
52
    editing = editmode ? 1 : 0;
 
53
    player1->state = editing ? CS_EDITING : CS_ALIVE;
 
54
    if(!force) addmsg(SV_EDITMODE, "ri", editing);
 
55
}
 
56
 
 
57
void edittoggle() { toggleedit(false); }
 
58
 
 
59
COMMAND(edittoggle, ARG_NONE);
 
60
 
 
61
char *editinfo()
 
62
{
 
63
    static string info;
 
64
    if(!editmode) return NULL;
 
65
    int e = closestent();
 
66
    if(e<0) return NULL;
 
67
    entity &c = ents[e];
 
68
    s_sprintf(info)("closest entity = %s (%d, %d, %d, %d), selection = (%d, %d)", entnames[c.type], c.attr1, c.attr2, c.attr3, c.attr4, sel.xs, sel.ys);
 
69
    return info;
 
70
}
 
71
 
 
72
void correctsel()                                       // ensures above invariant
 
73
{
 
74
    selset = !OUTBORD(sel.x, sel.y);
 
75
    int bsize = ssize-MINBORD;
 
76
    if(sel.xs+sel.x>bsize) sel.xs = bsize-sel.x;
 
77
    if(sel.ys+sel.y>bsize) sel.ys = bsize-sel.y;
 
78
    if(sel.xs<=0 || sel.ys<=0) selset = false;
 
79
}
 
80
 
 
81
bool noteditmode()
 
82
{
 
83
    correctsel();
 
84
    if(!editmode) conoutf("this function is only allowed in edit mode");
 
85
    return !editmode;
 
86
}
 
87
 
 
88
bool noselection()
 
89
{
 
90
    if(!selset) conoutf("no selection");
 
91
    return !selset;
 
92
}
 
93
 
 
94
#define EDITSEL   if(noteditmode() || noselection()) return;
 
95
#define EDITSELMP if(noteditmode() || noselection() || multiplayer()) return;
 
96
#define EDITMP    if(noteditmode() || multiplayer()) return;
 
97
 
 
98
void selectpos(int x, int y, int xs, int ys)
 
99
{
 
100
    block s = { x, y, xs, ys };
 
101
    sel = s;
 
102
    selh = 0;
 
103
    correctsel();
 
104
}
 
105
 
 
106
void makesel()
 
107
{
 
108
    block s = { min(lastx,cx), min(lasty,cy), abs(lastx-cx)+1, abs(lasty-cy)+1 };
 
109
    sel = s;
 
110
    selh = max(lasth,ch);
 
111
    correctsel();
 
112
    if(selset) rtex = *S(sel.x, sel.y);
 
113
}
 
114
 
 
115
VAR(flrceil,0,0,2);
 
116
VAR(editaxis,0,0,13);
 
117
 
 
118
// VC8 optimizer screws up rendering somehow if this is an actual function
 
119
#define sheight(s,t,z) (!flrceil ? (s->type==FHF ? s->floor-t->vdelta/4.0f : (float)s->floor) : (s->type==CHF ? s->ceil+t->vdelta/4.0f : (float)s->ceil))
 
120
 
 
121
void cursorupdate()                                     // called every frame from hud
 
122
{
 
123
    flrceil = ((int)(camera1->pitch>=0))*2;
 
124
    int cyaw = ((int) camera1->yaw) % 180;
 
125
    editaxis = editmode ? (fabs(camera1->pitch) > 65 ? 13 : (cyaw < 45 || cyaw > 135 ? 12 : 11)) : 0;
 
126
 
 
127
    volatile float x = worldpos.x;                      // volatile needed to prevent msvc7 optimizer bug?
 
128
    volatile float y = worldpos.y;
 
129
    volatile float z = worldpos.z;
 
130
 
 
131
    cx = (int)x;
 
132
    cy = (int)y;
 
133
 
 
134
    if(OUTBORD(cx, cy)) return;
 
135
    sqr *s = S(cx,cy);
 
136
 
 
137
    if(fabs(sheight(s,s,z)-z)>1)                        // selected wall
 
138
    {
 
139
        x += x>camera1->o.x ? 0.5f : -0.5f;             // find right wall cube
 
140
        y += y>camera1->o.y ? 0.5f : -0.5f;
 
141
 
 
142
        cx = (int)x;
 
143
        cy = (int)y;
 
144
 
 
145
        if(OUTBORD(cx, cy)) return;
 
146
    }
 
147
 
 
148
    if(dragging) makesel();
 
149
 
 
150
    const int GRIDSIZE = 5;
 
151
    const float GRIDW = 0.5f;
 
152
    const float GRID8 = 2.0f;
 
153
    const float GRIDS = 2.0f;
 
154
    const int GRIDM = 0x7;
 
155
 
 
156
    // render editing grid
 
157
 
 
158
    for(int ix = cx-GRIDSIZE; ix<=cx+GRIDSIZE; ix++) for(int iy = cy-GRIDSIZE; iy<=cy+GRIDSIZE; iy++)
 
159
    {
 
160
 
 
161
        if(OUTBORD(ix, iy)) continue;
 
162
        sqr *s = S(ix,iy);
 
163
        if(SOLID(s)) continue;
 
164
        float h1 = sheight(s, s, z);
 
165
        float h2 = sheight(s, SWS(s,1,0,sfactor), z);
 
166
        float h3 = sheight(s, SWS(s,1,1,sfactor), z);
 
167
        float h4 = sheight(s, SWS(s,0,1,sfactor), z);
 
168
        if(s->tag) linestyle(GRIDW, 0xFF, 0x40, 0x40);
 
169
        else if(s->type==FHF || s->type==CHF) linestyle(GRIDW, 0x80, 0xFF, 0x80);
 
170
        else linestyle(GRIDW, 0x80, 0x80, 0x80);
 
171
        block b = { ix, iy, 1, 1 };
 
172
        box(b, h1, h2, h3, h4);
 
173
        linestyle(GRID8, 0x40, 0x40, 0xFF);
 
174
        if(!(ix&GRIDM))   line(ix,   iy,   h1, ix,   iy+1, h4);
 
175
        if(!((ix+1)&GRIDM)) line(ix+1, iy,   h2, ix+1, iy+1, h3);
 
176
        if(!(iy&GRIDM))   line(ix,   iy,   h1, ix+1, iy,   h2);
 
177
        if(!((iy+1)&GRIDM)) line(ix,   iy+1, h4, ix+1, iy+1, h3);
 
178
    }
 
179
 
 
180
    if(!SOLID(s))
 
181
    {
 
182
        float ih = sheight(s, s, z);
 
183
        linestyle(GRIDS, 0xFF, 0xFF, 0xFF);
 
184
        block b = { cx, cy, 1, 1 };
 
185
        box(b, ih, sheight(s, SWS(s,1,0,sfactor), z), sheight(s, SWS(s,1,1,sfactor), z), sheight(s, SWS(s,0,1,sfactor), z));
 
186
        linestyle(GRIDS, 0xFF, 0x00, 0x00);
 
187
        dot(cx, cy, ih);
 
188
        ch = (int)ih;
 
189
    }
 
190
 
 
191
    if(selset)
 
192
    {
 
193
        linestyle(GRIDS, 0xFF, 0x40, 0x40);
 
194
        box(sel, (float)selh, (float)selh, (float)selh, (float)selh);
 
195
    }
 
196
 
 
197
    glLineWidth(1);
 
198
}
 
199
 
 
200
vector<block *> undos;                                  // unlimited undo
 
201
VAR(undomegs, 0, 1, 10);                                // bounded by n megs
 
202
 
 
203
void pruneundos(int maxremain)                          // bound memory
 
204
{
 
205
    int t = 0;
 
206
    loopvrev(undos)
 
207
    {
 
208
        t += undos[i]->xs*undos[i]->ys*sizeof(sqr);
 
209
        if(t>maxremain) delete[] (uchar *)undos.remove(i);
 
210
    }
 
211
}
 
212
 
 
213
void makeundo()
 
214
{
 
215
    undos.add(blockcopy(sel));
 
216
    pruneundos(undomegs<<20);
 
217
}
 
218
 
 
219
void editundo()
 
220
{
 
221
    EDITMP;
 
222
    if(undos.empty()) { conoutf("nothing more to undo"); return; }
 
223
    block *p = undos.pop();
 
224
    blockpaste(*p);
 
225
    freeblock(p);
 
226
}
 
227
 
 
228
block *copybuf = NULL;
 
229
 
 
230
void copy()
 
231
{
 
232
    EDITSELMP;
 
233
    freeblock(copybuf);
 
234
    copybuf = blockcopy(sel);
 
235
}
 
236
 
 
237
void paste()
 
238
{
 
239
    EDITMP;
 
240
    if(!copybuf) { conoutf("nothing to paste"); return; }
 
241
    sel.xs = copybuf->xs;
 
242
    sel.ys = copybuf->ys;
 
243
    correctsel();
 
244
    if(!selset || sel.xs!=copybuf->xs || sel.ys!=copybuf->ys) { conoutf("incorrect selection"); return; }
 
245
    makeundo();
 
246
    copybuf->x = sel.x;
 
247
    copybuf->y = sel.y;
 
248
    blockpaste(*copybuf);
 
249
}
 
250
 
 
251
void tofronttex()                                       // maintain most recently used of the texture lists when applying texture
 
252
{
 
253
    loopi(3)
 
254
    {
 
255
        int c = curedittex[i];
 
256
        if(c>=0)
 
257
        {
 
258
            uchar *p = hdr.texlists[i];
 
259
            int t = p[c];
 
260
            for(int a = c-1; a>=0; a--) p[a+1] = p[a];
 
261
            p[0] = t;
 
262
            curedittex[i] = -1;
 
263
        }
 
264
    }
 
265
}
 
266
 
 
267
void editdrag(bool isdown)
 
268
{
 
269
    if((dragging = isdown))
 
270
    {
 
271
        lastx = cx;
 
272
        lasty = cy;
 
273
        lasth = ch;
 
274
        selset = false;
 
275
        tofronttex();
 
276
    }
 
277
    makesel();
 
278
}
 
279
 
 
280
// the core editing function. all the *xy functions perform the core operations
 
281
// and are also called directly from the network, the function below it is strictly
 
282
// triggered locally. They all have very similar structure.
 
283
 
 
284
void editheightxy(bool isfloor, int amount, block &sel)
 
285
{
 
286
    loopselxy(if(isfloor)
 
287
    {
 
288
        s->floor += amount;
 
289
        if(s->floor>=s->ceil) s->floor = s->ceil-1;
 
290
    }
 
291
    else
 
292
    {
 
293
        s->ceil += amount;
 
294
        if(s->ceil<=s->floor) s->ceil = s->floor+1;
 
295
    });
 
296
}
 
297
 
 
298
void editheight(int flr, int amount)
 
299
{
 
300
    EDITSEL;
 
301
    bool isfloor = flr==0;
 
302
    editheightxy(isfloor, amount, sel);
 
303
    addmsg(SV_EDITH, "ri6", sel.x, sel.y, sel.xs, sel.ys, isfloor, amount);
 
304
}
 
305
 
 
306
COMMAND(editheight, ARG_2INT);
 
307
 
 
308
void edittexxy(int type, int t, block &sel)
 
309
{
 
310
    loopselxy(switch(type)
 
311
    {
 
312
        case 0: s->ftex = t; break;
 
313
        case 1: s->wtex = t; break;
 
314
        case 2: s->ctex = t; break;
 
315
        case 3: s->utex = t; break;
 
316
    });
 
317
}
 
318
 
 
319
void edittex(int type, int dir)
 
320
{
 
321
    EDITSEL;
 
322
    if(type<0 || type>3) return;
 
323
    if(type!=lasttype) { tofronttex(); lasttype = type; }
 
324
    int atype = type==3 ? 1 : type;
 
325
    int i = curedittex[atype];
 
326
    i = i<0 ? 0 : i+dir;
 
327
    curedittex[atype] = i = min(max(i, 0), 255);
 
328
    int t = lasttex = hdr.texlists[atype][i];
 
329
    edittexxy(type, t, sel);
 
330
    addmsg(SV_EDITT, "ri6", sel.x, sel.y, sel.xs, sel.ys, type, t);
 
331
}
 
332
 
 
333
void replace()
 
334
{
 
335
    EDITSELMP;
 
336
    loop(x,ssize) loop(y,ssize)
 
337
    {
 
338
        sqr *s = S(x, y);
 
339
        switch(lasttype)
 
340
        {
 
341
            case 0: if(s->ftex == rtex.ftex) s->ftex = lasttex; break;
 
342
            case 1: if(s->wtex == rtex.wtex) s->wtex = lasttex; break;
 
343
            case 2: if(s->ctex == rtex.ctex) s->ctex = lasttex; break;
 
344
            case 3: if(s->utex == rtex.utex) s->utex = lasttex; break;
 
345
        }
 
346
    }
 
347
    block b = { 0, 0, ssize, ssize };
 
348
    remip(b);
 
349
}
 
350
 
 
351
void edittypexy(int type, block &sel)
 
352
{
 
353
    loopselxy(s->type = type);
 
354
}
 
355
 
 
356
void edittype(int type)
 
357
{
 
358
    EDITSEL;
 
359
    if(type==CORNER && (sel.xs!=sel.ys || sel.xs==3 || (sel.xs>4 && sel.xs!=8)
 
360
                   || sel.x&~-sel.xs || sel.y&~-sel.ys))
 
361
                   { conoutf("corner selection must be power of 2 aligned"); return; }
 
362
    edittypexy(type, sel);
 
363
    addmsg(SV_EDITS, "ri5", sel.x, sel.y, sel.xs, sel.ys, type);
 
364
}
 
365
 
 
366
void heightfield(int t) { edittype(t==0 ? FHF : CHF); }
 
367
void solid(int t)       { edittype(t==0 ? SPACE : SOLID); }
 
368
void corner()           { edittype(CORNER); }
 
369
 
 
370
COMMAND(heightfield, ARG_1INT);
 
371
COMMAND(solid, ARG_1INT);
 
372
COMMAND(corner, ARG_NONE);
 
373
 
 
374
void editequalisexy(bool isfloor, block &sel)
 
375
{
 
376
    int low = 127, hi = -128;
 
377
    loopselxy(
 
378
    {
 
379
        if(s->floor<low) low = s->floor;
 
380
        if(s->ceil>hi) hi = s->ceil;
 
381
    });
 
382
    loopselxy(
 
383
    {
 
384
        if(isfloor) s->floor = low; else s->ceil = hi;
 
385
        if(s->floor>=s->ceil) s->floor = s->ceil-1;
 
386
    });
 
387
}
 
388
 
 
389
void equalize(int flr)
 
390
{
 
391
    bool isfloor = flr==0;
 
392
    EDITSEL;
 
393
    editequalisexy(isfloor, sel);
 
394
    addmsg(SV_EDITE, "ri5", sel.x, sel.y, sel.xs, sel.ys, isfloor);
 
395
}
 
396
 
 
397
COMMAND(equalize, ARG_1INT);
 
398
 
 
399
void setvdeltaxy(int delta, block &sel)
 
400
{
 
401
    loopselxy(s->vdelta = max(s->vdelta+delta, 0));
 
402
    remipmore(sel);
 
403
}
 
404
 
 
405
void setvdelta(int delta)
 
406
{
 
407
    EDITSEL;
 
408
    setvdeltaxy(delta, sel);
 
409
    addmsg(SV_EDITD, "ri5", sel.x, sel.y, sel.xs, sel.ys, delta);
 
410
}
 
411
 
 
412
const int MAXARCHVERT = 50;
 
413
int archverts[MAXARCHVERT][MAXARCHVERT];
 
414
bool archvinit = false;
 
415
 
 
416
void archvertex(int span, int vert, int delta)
 
417
{
 
418
    if(!archvinit)
 
419
    {
 
420
        archvinit = true;
 
421
        loop(s,MAXARCHVERT) loop(v,MAXARCHVERT) archverts[s][v] = 0;
 
422
    }
 
423
    if(span>=MAXARCHVERT || vert>=MAXARCHVERT || span<0 || vert<0) return;
 
424
    archverts[span][vert] = delta;
 
425
}
 
426
 
 
427
void arch(int sidedelta, int _a)
 
428
{
 
429
    EDITSELMP;
 
430
    sel.xs++;
 
431
    sel.ys++;
 
432
    if(sel.xs>MAXARCHVERT) sel.xs = MAXARCHVERT;
 
433
    if(sel.ys>MAXARCHVERT) sel.ys = MAXARCHVERT;
 
434
    loopselxy(s->vdelta =
 
435
        sel.xs>sel.ys
 
436
            ? (archverts[sel.xs-1][x] + (y==0 || y==sel.ys-1 ? sidedelta : 0))
 
437
            : (archverts[sel.ys-1][y] + (x==0 || x==sel.xs-1 ? sidedelta : 0)));
 
438
    remipmore(sel);
 
439
}
 
440
 
 
441
void slope(int xd, int yd)
 
442
{
 
443
    EDITSELMP;
 
444
    int off = 0;
 
445
    if(xd<0) off -= xd*sel.xs;
 
446
    if(yd<0) off -= yd*sel.ys;
 
447
    sel.xs++;
 
448
    sel.ys++;
 
449
    loopselxy(s->vdelta = xd*x+yd*y+off);
 
450
    remipmore(sel);
 
451
}
 
452
 
 
453
void perlin(int scale, int seed, int psize)
 
454
{
 
455
    EDITSELMP;
 
456
    sel.xs++;
 
457
    sel.ys++;
 
458
    makeundo();
 
459
    sel.xs--;
 
460
    sel.ys--;
 
461
    perlinarea(sel, scale, seed, psize);
 
462
    sel.xs++;
 
463
    sel.ys++;
 
464
    remipmore(sel);
 
465
    sel.xs--;
 
466
    sel.ys--;
 
467
}
 
468
 
 
469
VARF(fullbright, 0, 0, 1,
 
470
    if(fullbright)
 
471
    {
 
472
        if(noteditmode()) return;
 
473
        fullbrightlight();
 
474
    }
 
475
    else calclight();
 
476
);
 
477
 
 
478
void edittag(int tag)
 
479
{
 
480
    EDITSELMP;
 
481
    loopselxy(s->tag = tag);
 
482
}
 
483
 
 
484
void newent(char *what, char *a1, char *a2, char *a3, char *a4)
 
485
{
 
486
    EDITSEL;
 
487
    newentity(-1, sel.x, sel.y, (int)camera1->o.z, what, ATOI(a1), ATOI(a2), ATOI(a3), ATOI(a4));
 
488
}
 
489
 
 
490
COMMANDN(select, selectpos, ARG_4INT);
 
491
COMMAND(edittag, ARG_1INT);
 
492
COMMAND(replace, ARG_NONE);
 
493
COMMAND(archvertex, ARG_3INT);
 
494
COMMAND(arch, ARG_2INT);
 
495
COMMAND(slope, ARG_2INT);
 
496
COMMANDN(vdelta, setvdelta, ARG_1INT);
 
497
COMMANDN(undo, editundo, ARG_NONE);
 
498
COMMAND(copy, ARG_NONE);
 
499
COMMAND(paste, ARG_NONE);
 
500
COMMAND(edittex, ARG_2INT);
 
501
COMMAND(newent, ARG_5STR);
 
502
COMMAND(perlin, ARG_3INT);
 
503
 
 
504