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

« back to all changes in this revision

Viewing changes to source/src/entities.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
// entities.cpp: map entity related functions (pickup etc.)
 
2
 
 
3
#include "pch.h"
 
4
#include "cube.h"
 
5
 
 
6
vector<entity> ents;
 
7
 
 
8
const char *entnames[] =
 
9
{
 
10
    "none?", "light", "playerstart",
 
11
    "pistol", "ammobox","grenades",
 
12
    "health", "armour", "akimbo",
 
13
    "mapmodel", "trigger",
 
14
    "ladder", "ctf-flag",
 
15
    "sound", "clip", "", ""
 
16
};
 
17
 
 
18
const char *entmdlnames[] =
 
19
{
 
20
        "pickups/pistolclips", "pickups/ammobox", "pickups/nades", "pickups/health", "pickups/kevlar", "pickups/akimbo",
 
21
};
 
22
 
 
23
void renderent(entity &e)
 
24
{
 
25
    const char *mdlname = entmdlnames[e.type-I_CLIPS];
 
26
    float z = (float)(1+sinf(lastmillis/100.0f+e.x+e.y)/20),
 
27
          yaw = lastmillis/10.0f;
 
28
        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);
 
29
}
 
30
 
 
31
void renderclip(entity &e, bool ismm = false)
 
32
{
 
33
    float xradius = max(float(e.attr2), 0.1f), yradius = max(float(e.attr3), 0.1f);
 
34
    vec bbmin(e.x - xradius, e.y - yradius, float(S(e.x, e.y)->floor+e.attr1)),
 
35
        bbmax(e.x + xradius, e.y + yradius, bbmin.z + max(float(e.attr4), 0.1f));
 
36
 
 
37
    glDisable(GL_TEXTURE_2D);
 
38
    if(ismm) linestyle(1, 0, 0xFF, 0);
 
39
    else linestyle(1, 0xFF, 0xFF, 0);
 
40
    glBegin(GL_LINES);
 
41
 
 
42
    glVertex3f(bbmin.x, bbmin.y, bbmin.z);
 
43
    loopi(2) glVertex3f(bbmax.x, bbmin.y, bbmin.z);
 
44
    loopi(2) glVertex3f(bbmax.x, bbmax.y, bbmin.z);
 
45
    loopi(2) glVertex3f(bbmin.x, bbmax.y, bbmin.z);
 
46
    glVertex3f(bbmin.x, bbmin.y, bbmin.z);
 
47
 
 
48
    glVertex3f(bbmin.x, bbmin.y, bbmax.z);
 
49
    loopi(2) glVertex3f(bbmax.x, bbmin.y, bbmax.z);
 
50
    loopi(2) glVertex3f(bbmax.x, bbmax.y, bbmax.z);
 
51
    loopi(2) glVertex3f(bbmin.x, bbmax.y, bbmax.z);
 
52
    glVertex3f(bbmin.x, bbmin.y, bbmax.z);
 
53
 
 
54
    loopi(8) glVertex3f(i&2 ? bbmax.x : bbmin.x, i&4 ? bbmax.y : bbmin.y, i&1 ? bbmax.z : bbmin.z);
 
55
 
 
56
    glEnd();
 
57
    glEnable(GL_TEXTURE_2D);
 
58
}
 
59
 
 
60
void rendermapmodels()
 
61
{
 
62
    loopv(ents)
 
63
    {
 
64
        entity &e = ents[i];
 
65
        if(e.type==MAPMODEL)
 
66
        {
 
67
            mapmodelinfo &mmi = getmminfo(e.attr2);
 
68
            if(!&mmi) continue;
 
69
            rendermodel(mmi.name, ANIM_MAPMODEL|ANIM_LOOP, e.attr4, 0, vec(e.x, e.y, (float)S(e.x, e.y)->floor+mmi.zoff+e.attr3), (float)((e.attr1+7)-(e.attr1+7)%15), 0, 10.0f);
 
70
        }
 
71
    }
 
72
}
 
73
 
 
74
VAR(showmodelclipping, 0, 0, 1);
 
75
 
 
76
void renderentities()
 
77
{
 
78
    if(editmode && !reflecting && !refracting && !stenciling)
 
79
    {
 
80
        static int lastsparkle = 0;
 
81
        if(lastmillis - lastsparkle >= 20)
 
82
        {
 
83
            lastsparkle = lastmillis - (lastmillis%20);
 
84
            int closest = closestent();
 
85
            loopv(ents)
 
86
            {
 
87
                entity &e = ents[i];
 
88
                if(e.type==NOTUSED) continue;
 
89
                vec v(e.x, e.y, e.z);
 
90
                if(vec(v).sub(camera1->o).dot(camdir) < 0) continue;
 
91
                particle_splash(i == closest ? 12 : 2, 2, 40, v);
 
92
            }
 
93
        }
 
94
    }
 
95
    loopv(ents)
 
96
    {
 
97
        entity &e = ents[i];
 
98
        if(isitem(e.type))
 
99
        {
 
100
            if((!OUTBORD(e.x, e.y) && e.spawned) || editmode)
 
101
            {
 
102
                renderent(e);
 
103
            }
 
104
        }
 
105
        else if(editmode)
 
106
        {
 
107
            if(e.type==CTF_FLAG)
 
108
            {
 
109
                s_sprintfd(path)("pickups/flags/%s", team_string(e.attr2));
 
110
                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);
 
111
            }
 
112
            else if(e.type==CLIP && !stenciling) renderclip(e);
 
113
            else if(showmodelclipping && e.type == MAPMODEL && !stenciling)
 
114
            {
 
115
                mapmodelinfo &mmi = getmminfo(e.attr2);
 
116
                if(&mmi && mmi.h)
 
117
                {
 
118
                    entity ce = e;
 
119
                    ce.type = CLIP;
 
120
                    ce.attr1 = mmi.zoff+e.attr3;
 
121
                    ce.attr2 = ce.attr3 = mmi.rad;
 
122
                    ce.attr4 = mmi.h;
 
123
                    renderclip(ce, true);
 
124
                }
 
125
            }
 
126
        }
 
127
    }
 
128
    if(m_flags) loopi(2)
 
129
    {
 
130
        flaginfo &f = flaginfos[i];
 
131
        switch(f.state)
 
132
        {
 
133
            case CTFF_STOLEN:
 
134
                if(f.actor && f.actor != player1)
 
135
                {
 
136
                    if(OUTBORD(f.actor->o.x, f.actor->o.y)) break;
 
137
                    s_sprintfd(path)("pickups/flags/small_%s%s", m_ktf ? "" : team_string(i), m_htf ? "_htf" : m_ktf ? "ktf" : "");
 
138
                    rendermodel(path, ANIM_FLAG|ANIM_START|ANIM_DYNALLOC, 0, 0, vec(f.actor->o).add(vec(0, 0, 0.3f+(sinf(lastmillis/100.0f)+1)/10)), lastmillis/2.5f, 0, 120.0f);
 
139
                }
 
140
                break;
 
141
            case CTFF_INBASE:
 
142
                if(!numflagspawn[i]) break;
 
143
            case CTFF_DROPPED:
 
144
            {
 
145
                if(OUTBORD(f.pos.x, f.pos.y)) break;
 
146
                entity &e = *f.flagent;
 
147
                s_sprintfd(path)("pickups/flags/%s%s", m_ktf ? "" : team_string(i),  m_htf ? "_htf" : m_ktf ? "ktf" : "");
 
148
                rendermodel(path, ANIM_FLAG|ANIM_LOOP, 0, 0, vec(f.pos.x, f.pos.y, f.state==CTFF_INBASE ? (float)S(int(f.pos.x), int(f.pos.y))->floor : f.pos.z), (float)((e.attr1+7)-(e.attr1+7)%15), 0, 120.0f);
 
149
                break;
 
150
            }
 
151
            case CTFF_IDLE:
 
152
                break;
 
153
        }
 
154
    }
 
155
}
 
156
 
 
157
// these two functions are called when the server acknowledges that you really
 
158
// picked up the item (in multiplayer someone may grab it before you).
 
159
 
 
160
void pickupeffects(int n, playerent *d)
 
161
{
 
162
    if(!ents.inrange(n)) return;
 
163
    entity &e = ents[n];
 
164
    e.spawned = false;
 
165
    if(!d) return;
 
166
    d->pickup(e.type);
 
167
    itemstat &is = d->itemstats(e.type);
 
168
    if(d!=player1 && d->type!=ENT_BOT) return;
 
169
    if(&is)
 
170
    {
 
171
        if(d==player1) playsoundc(is.sound);
 
172
        else playsound(is.sound, d);
 
173
    }
 
174
 
 
175
    weapon *w = NULL;
 
176
    switch(e.type)
 
177
    {
 
178
        case I_AKIMBO: w = d->weapons[GUN_AKIMBO]; break;
 
179
        case I_CLIPS: w = d->weapons[GUN_PISTOL]; break;
 
180
        case I_AMMO: w = d->primweap; break;
 
181
        case I_GRENADE: w = d->weapons[GUN_GRENADE]; break;
 
182
    }
 
183
    if(w) w->onammopicked();
 
184
}
 
185
 
 
186
// these functions are called when the client touches the item
 
187
 
 
188
void trypickup(int n, playerent *d)
 
189
{
 
190
    entity &e = ents[n];
 
191
    switch(e.type)
 
192
    {
 
193
        default:
 
194
            if(d->canpickup(e.type))
 
195
            {
 
196
                if(d->type==ENT_PLAYER) addmsg(SV_ITEMPICKUP, "ri", n);
 
197
                else if(d->type==ENT_BOT && serverpickup(n, -1)) pickupeffects(n, d);
 
198
                e.spawned = false;
 
199
            }
 
200
            break;
 
201
 
 
202
        case LADDER:
 
203
            if(!d->crouching) d->onladder = true;
 
204
            break;
 
205
    }
 
206
}
 
207
 
 
208
void trypickupflag(int flag, playerent *d)
 
209
{
 
210
    if(d==player1)
 
211
    {
 
212
        flaginfo &f = flaginfos[flag];
 
213
        flaginfo &of = flaginfos[team_opposite(flag)];
 
214
        if(f.state == CTFF_STOLEN) return;
 
215
        bool own = flag == team_int(d->team);
 
216
 
 
217
        if(m_ctf)
 
218
        {
 
219
            if(own) // it's the own flag
 
220
            {
 
221
                if(f.state == CTFF_DROPPED) flagreturn(flag);
 
222
                else if(f.state == CTFF_INBASE && of.state == CTFF_STOLEN && of.actor == d && of.ack) flagscore(of.team);
 
223
            }
 
224
            else flagpickup(flag);
 
225
        }
 
226
        else if(m_htf)
 
227
        {
 
228
            if(own)
 
229
            {
 
230
                flagpickup(flag);
 
231
            }
 
232
            else
 
233
            {
 
234
                if(f.state == CTFF_DROPPED) flagscore(f.team); // may not count!
 
235
            }
 
236
        }
 
237
        else if(m_ktf)
 
238
        {
 
239
            if(f.state != CTFF_INBASE) return;
 
240
            flagpickup(flag);
 
241
        }
 
242
    }
 
243
}
 
244
 
 
245
void checkitems(playerent *d)
 
246
{
 
247
    if(editmode || d->state!=CS_ALIVE) return;
 
248
    d->onladder = false;
 
249
    float eyeheight = d->eyeheight;
 
250
    loopv(ents)
 
251
    {
 
252
        entity &e = ents[i];
 
253
        if(e.type==NOTUSED) continue;
 
254
        if(e.type==LADDER)
 
255
        {
 
256
            if(OUTBORD(e.x, e.y)) continue;
 
257
            vec v(e.x, e.y, d->o.z);
 
258
            float dist1 = d->o.dist(v);
 
259
            float dist2 = d->o.z - (S(e.x, e.y)->floor+eyeheight);
 
260
            if(dist1<1.5f && dist2<e.attr1) trypickup(i, d);
 
261
            continue;
 
262
        }
 
263
 
 
264
        if(!e.spawned) continue;
 
265
        if(OUTBORD(e.x, e.y)) continue;
 
266
 
 
267
        if(e.type==CTF_FLAG) continue;
 
268
        // simple 2d collision
 
269
        vec v(e.x, e.y, S(e.x, e.y)->floor+eyeheight);
 
270
        if(isitem(e.type)) v.z += e.attr1;
 
271
        if(d->o.dist(v)<2.5f) trypickup(i, d);
 
272
    }
 
273
    if(m_flags) loopi(2)
 
274
    {
 
275
        flaginfo &f = flaginfos[i];
 
276
        entity &e = *f.flagent;
 
277
        if(!e.spawned || !f.ack || (f.state == CTFF_INBASE && !numflagspawn[i])) continue;
 
278
        if(OUTBORD(f.pos.x, f.pos.y)) continue;
 
279
        if(f.state==CTFF_DROPPED) // 3d collision for dropped ctf flags
 
280
        {
 
281
            if(objcollide(d, f.pos, 2.5f, 4.0f)) trypickupflag(i, d);
 
282
        }
 
283
        else // simple 2d collision
 
284
        {
 
285
            vec v = f.pos;
 
286
            v.z = S(int(v.x), int(v.y))->floor + eyeheight;
 
287
            if(d->o.dist(v)<2.5f) trypickupflag(i, d);
 
288
        }
 
289
    }
 
290
}
 
291
 
 
292
void putitems(ucharbuf &p)            // puts items in network stream and also spawns them locally
 
293
{
 
294
    loopv(ents) if(ents[i].fitsmode(gamemode) || (multiplayer(false) && gamespeed!=100 && (i=-1)))
 
295
    {
 
296
        putint(p, i);
 
297
        putint(p, ents[i].type);
 
298
        ents[i].spawned = true;
 
299
    }
 
300
}
 
301
 
 
302
void resetspawns()
 
303
{
 
304
        loopv(ents) ents[i].spawned = false;
 
305
        if(m_noitemsnade || m_pistol)
 
306
    {
 
307
                loopv(ents) ents[i].transformtype(gamemode);
 
308
    }
 
309
}
 
310
void setspawn(int i, bool on) { if(ents.inrange(i)) ents[i].spawned = on; }
 
311
 
 
312
bool selectnextprimary(int num)
 
313
{
 
314
    switch(num)
 
315
    {
 
316
        case GUN_SHOTGUN:
 
317
        case GUN_SUBGUN:
 
318
        case GUN_SNIPER:
 
319
        case GUN_ASSAULT:
 
320
            player1->setnextprimary(num);
 
321
            addmsg(SV_PRIMARYWEAP, "ri", player1->nextprimweap->type);
 
322
            return true;
 
323
 
 
324
        default:
 
325
            conoutf("this is not a valid primary weapon");
 
326
            return false;
 
327
    }
 
328
}
 
329
 
 
330
VARFP(nextprimary, 0, GUN_ASSAULT, NUMGUNS,
 
331
{
 
332
    if(!selectnextprimary(nextprimary)) selectnextprimary((nextprimary = GUN_ASSAULT));
 
333
});
 
334
 
 
335
// flag ent actions done by the local player
 
336
 
 
337
int flagdropmillis = 0;
 
338
 
 
339
void flagpickup(int fln)
 
340
{
 
341
    if(flagdropmillis && flagdropmillis>lastmillis) return;
 
342
        flaginfo &f = flaginfos[fln];
 
343
        f.flagent->spawned = false;
 
344
        f.state = CTFF_STOLEN;
 
345
        f.actor = player1; // do this although we don't know if we picked the flag to avoid getting it after a possible respawn
 
346
        f.actor_cn = getclientnum();
 
347
        f.ack = false;
 
348
        addmsg(SV_FLAGACTION, "rii", FA_PICKUP, f.team);
 
349
}
 
350
 
 
351
void tryflagdrop(bool manual)
 
352
{
 
353
    loopi(2)
 
354
    {
 
355
        flaginfo &f = flaginfos[i];
 
356
        if(f.state==CTFF_STOLEN && f.actor==player1)
 
357
        {
 
358
            f.flagent->spawned = false;
 
359
            f.state = CTFF_DROPPED;
 
360
            f.ack = false;
 
361
            flagdropmillis = lastmillis+3000;
 
362
            addmsg(SV_FLAGACTION, "rii", manual ? FA_DROP : FA_LOST, f.team);
 
363
        }
 
364
    }
 
365
}
 
366
 
 
367
void flagreturn(int fln)
 
368
{
 
369
        flaginfo &f = flaginfos[fln];
 
370
        f.flagent->spawned = false;
 
371
        f.ack = false;
 
372
        addmsg(SV_FLAGACTION, "rii", FA_RETURN, f.team);
 
373
}
 
374
 
 
375
void flagscore(int fln)
 
376
{
 
377
        flaginfo &f = flaginfos[fln];
 
378
        f.ack = false;
 
379
        addmsg(SV_FLAGACTION, "rii", FA_SCORE, f.team);
 
380
}
 
381
 
 
382
// flag ent actions from the net
 
383
 
 
384
void flagstolen(int flag, int act)
 
385
{
 
386
        playerent *actor = act == getclientnum() ? player1 : getclient(act);
 
387
        flaginfo &f = flaginfos[flag];
 
388
        f.actor = actor; // could be NULL if we just connected
 
389
        f.actor_cn = act;
 
390
        f.flagent->spawned = false;
 
391
        f.ack = true;
 
392
}
 
393
 
 
394
void flagdropped(int flag, float x, float y, float z)
 
395
{
 
396
        flaginfo &f = flaginfos[flag];
 
397
    if(OUTBORD(x, y)) return; // valid pos
 
398
    bounceent p;
 
399
    p.rotspeed = 0.0f;
 
400
    p.o.x = x;
 
401
    p.o.y = y;
 
402
    p.o.z = z;
 
403
    p.vel.z = -0.8f;
 
404
    p.aboveeye = p.eyeheight = p.maxeyeheight = 0.4f;
 
405
    p.radius = 0.1f;
 
406
 
 
407
    bool oldcancollide = false;
 
408
    if(f.actor)
 
409
    {
 
410
        oldcancollide = f.actor->cancollide;
 
411
        f.actor->cancollide = false; // avoid collision with owner
 
412
    }
 
413
    loopi(100) // perform physics steps
 
414
    {
 
415
        moveplayer(&p, 10, true, 50);
 
416
        if(p.stuck) break;
 
417
    }
 
418
    if(f.actor) f.actor->cancollide = oldcancollide; // restore settings
 
419
 
 
420
    f.pos.x = round(p.o.x);
 
421
    f.pos.y = round(p.o.y);
 
422
    f.pos.z = round(p.o.z);
 
423
    if(f.pos.z < hdr.waterlevel) f.pos.z = (short) hdr.waterlevel;
 
424
        f.flagent->spawned = true;
 
425
        f.ack = true;
 
426
}
 
427
 
 
428
void flaginbase(int flag)
 
429
{
 
430
        flaginfo &f = flaginfos[flag];
 
431
        f.actor = NULL; f.actor_cn = -1;
 
432
    f.pos = vec(f.flagent->x, f.flagent->y, f.flagent->z);
 
433
        f.flagent->spawned = true;
 
434
        f.ack = true;
 
435
}
 
436
 
 
437
void flagidle(int flag)
 
438
{
 
439
    flaginbase(flag);
 
440
        flaginfos[flag].flagent->spawned = false;
 
441
}
 
442
 
 
443
void entstats(void)
 
444
{
 
445
    int entcnt[MAXENTTYPES] = {0}, clipents = 0, spawncnt[5] = {0};
 
446
    loopv(ents)
 
447
    {
 
448
        entity &e = ents[i];
 
449
        if(e.type >= MAXENTTYPES) continue;
 
450
        entcnt[e.type]++;
 
451
        switch(e.type)
 
452
        {
 
453
            case MAPMODEL:
 
454
            {
 
455
                mapmodelinfo &mmi = getmminfo(e.attr2);
 
456
                if(&mmi && mmi.h) clipents++;
 
457
                break;
 
458
            }
 
459
            case PLAYERSTART:
 
460
                if(e.attr2 < 2) spawncnt[e.attr2]++;
 
461
                if(e.attr2 == 100) spawncnt[2]++;
 
462
                break;
 
463
            case CTF_FLAG:
 
464
                if(e.attr2 < 2) spawncnt[e.attr2 + 3]++;
 
465
                break;
 
466
        }
 
467
    }
 
468
    loopi(MAXENTTYPES)
 
469
    {
 
470
        if(entcnt[i]) switch(i)
 
471
        {
 
472
            case MAPMODEL:      conoutf(" %d %s, %d clipped", entcnt[i], entnames[i], clipents); break;
 
473
            case PLAYERSTART:   conoutf(" %d %s, %d CLA, %d RVSF, %d FFA", entcnt[i], entnames[i], spawncnt[0], spawncnt[1], spawncnt[2]); break;
 
474
            case CTF_FLAG:      conoutf(" %d %s, %d CLA, %d RVSF", entcnt[i], entnames[i], spawncnt[3], spawncnt[4]); break;
 
475
            default:            conoutf(" %d %s", entcnt[i], entnames[i]); break;
 
476
        }
 
477
    }
 
478
    conoutf("total entities: %d", ents.length());
 
479
}
 
480
 
 
481
COMMAND(entstats, ARG_NONE);
 
482