]> git.jsancho.org Git - lugaru.git/blob - Source/Objects/Weapons.cpp
Replaced patchobjects arrays by vectors, cleaned code a bit
[lugaru.git] / Source / Objects / Weapons.cpp
1 /*
2 Copyright (C) 2003, 2010 - Wolfire Games
3 Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
4
5 This file is part of Lugaru.
6
7 This file is part of Lugaru.
8
9 Lugaru is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 Lugaru is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "Objects/Weapons.hpp"
24
25 #include "Animation/Animation.hpp"
26 #include "Audio/openal_wrapper.hpp"
27 #include "Audio/Sounds.hpp"
28 #include "Game.hpp"
29 #include "Level/Awards.hpp"
30 #include "Tutorial.hpp"
31
32 extern float multiplier;
33 extern Terrain terrain;
34 extern float gravity;
35 extern int environment;
36 extern int detail;
37 extern FRUSTUM frustum;
38 extern XYZ viewer;
39 extern float realmultiplier;
40 extern int slomo;
41 extern float slomodelay;
42 extern bool cellophane;
43 extern float texdetail;
44 extern GLubyte bloodText[512 * 512 * 3];
45 extern int bloodtoggle;
46 extern bool autoslomo;
47 extern float camerashake;
48 extern float woozy;
49 extern float viewdistance;
50 extern float blackout;
51 extern bool freeze;
52 extern int numthrowkill;
53
54 Model Weapon::throwingknifemodel;
55 Texture Weapon::knifetextureptr;
56 Texture Weapon::lightbloodknifetextureptr;
57 Texture Weapon::bloodknifetextureptr;
58
59 Model Weapon::swordmodel;
60 Texture Weapon::swordtextureptr;
61 Texture Weapon::lightbloodswordtextureptr;
62 Texture Weapon::bloodswordtextureptr;
63
64 Model Weapon::staffmodel;
65 Texture Weapon::stafftextureptr;
66
67 Weapon::Weapon(int t, int o) : owner(o)
68 {
69     setType(t);
70     bloody = 0;
71     blooddrip = 0;
72     blooddripdelay = 0;
73     onfire = 0;
74     flamedelay = 0;
75     damage = 0;
76     position = -1000;
77     tippoint = -1000;
78 }
79
80 void Weapon::setType(int t)
81 {
82     type = t;
83     if (type == sword) {
84         mass = 1.5;
85         tipmass = 1;
86         length = .8;
87     }
88     if (type == staff) {
89         mass = 2;
90         tipmass = 1;
91         length = 1.5;
92     }
93     if (type == knife) {
94         mass = 1;
95         tipmass = 1.2;
96         length = .25;
97     }
98 }
99
100 /* Load weapons models and textures */
101 void Weapon::Load()
102 {
103     LOG("Loading weapon data...");
104
105     knifetextureptr.load("Textures/Knife.png", 0);
106     bloodknifetextureptr.load("Textures/BloodKnife.png", 0);
107     lightbloodknifetextureptr.load("Textures/BloodKnifeLight.png", 0);
108     swordtextureptr.load("Textures/Sword.jpg", 1);
109     bloodswordtextureptr.load("Textures/SwordBlood.jpg", 1);
110     lightbloodswordtextureptr.load("Textures/SwordBloodLight.jpg", 1);
111     stafftextureptr.load("Textures/Staff.jpg", 1);
112
113     throwingknifemodel.load("Models/ThrowingKnife.solid");
114     throwingknifemodel.Scale(.001, .001, .001);
115     throwingknifemodel.Rotate(90, 0, 0);
116     throwingknifemodel.Rotate(0, 90, 0);
117     throwingknifemodel.flat = 0;
118     throwingknifemodel.CalculateNormals(1);
119
120     swordmodel.load("Models/Sword.solid");
121     swordmodel.Scale(.001, .001, .001);
122     swordmodel.Rotate(90, 0, 0);
123     swordmodel.Rotate(0, 90, 0);
124     swordmodel.Rotate(0, 0, 90);
125     swordmodel.flat = 1;
126     swordmodel.CalculateNormals(1);
127
128     staffmodel.load("Models/Staff.solid");
129     staffmodel.Scale(.005, .005, .005);
130     staffmodel.Rotate(90, 0, 0);
131     staffmodel.Rotate(0, 90, 0);
132     staffmodel.Rotate(0, 0, 90);
133     staffmodel.flat = 1;
134     staffmodel.CalculateNormals(1);
135 }
136
137 void Weapon::doStuff(int i)
138 {
139     static int whichpatchx, whichpatchz, whichhit;
140     static XYZ start, end, colpoint, normalrot, footvel, footpoint;
141     static XYZ terrainnormal;
142     static XYZ vel;
143     static XYZ midp;
144     static XYZ newpoint1, newpoint2;
145     static float friction = 3.5;
146     static float elasticity = .4;
147     static XYZ bounceness;
148     static float frictionness;
149     static float closestdistance;
150     static float distance;
151     static XYZ point[3];
152     static XYZ closestpoint;
153     static XYZ closestswordpoint;
154     static float tempmult;
155
156     if (multiplier <= 0) {
157         return;
158     }
159
160     if (owner != -1) {
161         oldowner = owner;
162     }
163     if (damage >= 2 && type == staff && owner != -1) { // the staff breaks
164         emit_sound_at(staffbreaksound, tippoint);
165         XYZ tempvel;
166         for (int j = 0; j < 40; j++) {
167             tempvel.x = float(abs(Random() % 100) - 50) / 20;
168             tempvel.y = float(abs(Random() % 100) - 50) / 20;
169             tempvel.z = float(abs(Random() % 100) - 50) / 20;
170             Sprite::MakeSprite(splintersprite, position + (tippoint - position) * ((float)j - 8) / 32, tempvel * .5, 115 / 255, 73 / 255, 12 / 255, .1, 1);
171         }
172         if (owner != -1) {
173             Person::players[owner]->weaponactive = -1;
174             Person::players[owner]->num_weapons--;
175             if (Person::players[owner]->num_weapons) {
176                 Person::players[owner]->weaponids[0] = Person::players[owner]->weaponids[Person::players[owner]->num_weapons];
177                 if (Person::players[owner]->weaponstuck == Person::players[owner]->num_weapons)
178                     Person::players[owner]->weaponstuck = 0;
179             }
180         }
181         owner = -1;
182         hitsomething = 0;
183         missed = 1;
184         freetime = 0;
185         firstfree = 1;
186         position = 0;
187         physics = 0;
188     }
189     oldposition = position;
190     oldtippoint = tippoint;
191     if (owner == -1 && (velocity.x || velocity.y || velocity.z) && !physics) { // if the weapon is flying
192         position += velocity * multiplier;
193         tippoint += velocity * multiplier;
194         whichpatchx = position.x / (terrain.size / subdivision * terrain.scale);
195         whichpatchz = position.z / (terrain.size / subdivision * terrain.scale);
196         if (whichpatchx > 0 && whichpatchz > 0 && whichpatchx < subdivision && whichpatchz < subdivision) {
197             for (unsigned int j = 0; j < terrain.patchobjects[whichpatchx][whichpatchz].size(); j++) { // check for collision
198                 unsigned int k = terrain.patchobjects[whichpatchx][whichpatchz][j];
199                 start = oldtippoint;
200                 end = tippoint;
201                 whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
202                 if (whichhit != -1) {
203                     if (Object::objects[k]->type == treetrunktype) {
204                         Object::objects[k]->model.MakeDecal(breakdecal, DoRotation(colpoint - Object::objects[k]->position, 0, -Object::objects[k]->yaw, 0), .1, 1, Random() % 360);
205                         normalrot = DoRotation(Object::objects[k]->model.Triangles[whichhit].facenormal, 0, Object::objects[k]->yaw, 0);
206                         velocity = 0;
207                         if (type == knife)
208                             position = colpoint - normalrot * .1;
209                         else if (type == sword)
210                             position = colpoint - normalrot * .2;
211                         else if (type == staff)
212                             position = colpoint - normalrot * .2;
213                         XYZ temppoint1, temppoint2;
214                         float distance;
215
216                         temppoint1 = 0;
217                         temppoint2 = normalrot;
218                         distance = findDistance(&temppoint1, &temppoint2);
219                         rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
220                         rotation2 *= 360 / 6.28;
221                         temppoint1.y = 0;
222                         temppoint2.y = 0;
223                         rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
224                         rotation1 *= 360 / 6.28;
225                         if (temppoint1.x > temppoint2.x)
226                             rotation1 = 360 - rotation1;
227
228                         rotation3 = 0;
229                         smallrotation = 90;
230                         smallrotation2 = 0;
231                         bigtilt = 0;
232                         bigtilt2 = 0;
233                         bigrotation = 0;
234
235                         emit_sound_at(knifesheathesound, position, 128.);
236
237                         bloody = 0;
238
239                         Sprite::MakeSprite(cloudimpactsprite, position, velocity, 1, 1, 1, .8, .3);
240                     } else {
241                         physics = 1;
242                         firstfree = 1;
243                         position -= velocity * multiplier;
244                         tippoint -= velocity * multiplier;
245                         tipvelocity = velocity;
246                     }
247                 }
248             }
249         }
250
251         if (velocity.x || velocity.y || velocity.z) {
252             for (unsigned j = 0; j < Person::players.size(); j++) {
253                 footvel = 0;
254                 footpoint = DoRotation((Person::players[j]->jointPos(abdomen) + Person::players[j]->jointPos(neck)) / 2, 0, Person::players[j]->yaw, 0) * Person::players[j]->scale + Person::players[j]->coords;
255                 if (owner == -1 && distsqflat(&position, &Person::players[j]->coords) < 1.5 &&
256                         distsq(&position, &Person::players[j]->coords) < 4 && Person::players[j]->weaponstuck == -1 &&
257                         !Person::players[j]->skeleton.free && (int(j) != oldowner)) {
258                     if ((Person::players[j]->aitype != attacktypecutoff || abs(Random() % 6) == 0 || (Person::players[j]->animTarget != backhandspringanim && Person::players[j]->animTarget != rollanim && Person::players[j]->animTarget != flipanim && Random() % 2 == 0)) && !missed) {
259                         if ( (Person::players[j]->creature == wolftype && Random() % 3 != 0 && Person::players[j]->weaponactive == -1 && (Person::players[j]->isIdle() || Person::players[j]->isRun() || Person::players[j]->animTarget == walkanim)) ||
260                                 (Person::players[j]->creature == rabbittype && Random() % 2 == 0 && Person::players[j]->aitype == attacktypecutoff && Person::players[j]->weaponactive == -1)) {
261                             emit_sound_at(knifedrawsound, Person::players[j]->coords, 128.);
262
263                             Person::players[j]->animTarget = removeknifeanim;
264                             Person::players[j]->frameTarget = 1;
265                             Person::players[j]->target = 1;
266                             Person::players[j]->takeWeapon(i);
267
268                             Person::players[j]->aitype = attacktypecutoff;
269                         } else {
270                             if (j != 0)
271                                 numthrowkill++;
272                             Person::players[j]->num_weapons++;
273                             Person::players[j]->weaponstuck = Person::players[j]->num_weapons - 1;
274                             if (normaldotproduct(Person::players[j]->facing, velocity) > 0)
275                                 Person::players[j]->weaponstuckwhere = 1;
276                             else
277                                 Person::players[j]->weaponstuckwhere = 0;
278
279                             Person::players[j]->weaponids[Person::players[j]->num_weapons - 1] = i;
280
281                             Person::players[j]->RagDoll(0);
282                             Person::players[j]->jointVel(abdomen) += velocity * 2;
283                             Person::players[j]->jointVel(neck) += velocity * 2;
284                             Person::players[j]->jointVel(rightshoulder) += velocity * 2;
285                             Person::players[j]->jointVel(leftshoulder) += velocity * 2;
286                             if (bloodtoggle && !Tutorial::active)
287                                 Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3);
288                             if (Tutorial::active)
289                                 Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 1, 1, .8, .3);
290                             footvel = tippoint - position;
291                             Normalise(&footvel);
292                             if (bloodtoggle && !Tutorial::active)
293                                 Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * -1, 1, 0, 0, .6, 1);
294
295                             if (!Tutorial::active) {
296                                 if (Person::players[j]->weaponstuckwhere == 0)
297                                     Person::players[j]->DoBloodBig(2, 205);
298                                 if (Person::players[j]->weaponstuckwhere == 1)
299                                     Person::players[j]->DoBloodBig(2, 200);
300                                 Person::players[j]->damage += 200 / Person::players[j]->armorhigh;
301                                 Person::players[j]->deathbleeding = 1;
302                                 Person::players[j]->bloodloss += (200 + abs((float)(Random() % 40)) - 20) / Person::players[j]->armorhigh;
303                                 owner = j;
304                                 bloody = 2;
305                                 blooddrip = 5;
306                             }
307
308                             emit_sound_at(fleshstabsound, position, 128.);
309
310                             if (Animation::animations[Person::players[0]->animTarget].height == highheight)
311                                 award_bonus(0, ninja);
312                             else
313                                 award_bonus(0, Bullseyebonus);
314                         }
315                     } else {
316                         missed = 1;
317                     }
318                 }
319             }
320         }
321         if (position.y < terrain.getHeight(position.x, position.z)) {
322             if (terrain.getOpacity(position.x, position.z) < .2) {
323                 velocity = 0;
324                 if (terrain.lineTerrain(oldposition, position, &colpoint) != -1) {
325                     position = colpoint * terrain.scale;
326                 } else {
327                     position.y = terrain.getHeight(position.x, position.z);
328                 }
329
330                 terrain.MakeDecal(shadowdecalpermanent, position, .06, .5, 0);
331                 normalrot = terrain.getNormal(position.x, position.z) * -1;
332                 velocity = 0;
333                 glMatrixMode(GL_MODELVIEW);
334                 glPushMatrix();
335                 GLfloat M[16];
336                 glLoadIdentity();
337                 glRotatef(bigrotation, 0, 1, 0);
338                 glRotatef(bigtilt2, 1, 0, 0);
339                 glRotatef(bigtilt, 0, 0, 1);
340                 glRotatef(-rotation1 + 90, 0, 1, 0);
341                 glRotatef(-rotation2 + 90, 0, 0, 1);
342                 glRotatef(-rotation3, 0, 1, 0);
343                 glRotatef(smallrotation, 1, 0, 0);
344                 glRotatef(smallrotation2, 0, 1, 0);
345                 glTranslatef(0, 0, 1);
346                 glGetFloatv(GL_MODELVIEW_MATRIX, M);
347                 tippoint.x = M[12];
348                 tippoint.y = M[13];
349                 tippoint.z = M[14];
350                 glPopMatrix();
351                 position -= tippoint * .15;
352                 XYZ temppoint1, temppoint2;
353
354                 rotation3 = 0;
355                 smallrotation = 90;
356                 smallrotation2 = 0;
357                 bigtilt = 0;
358                 bigtilt2 = 0;
359                 bigrotation = 0;
360
361                 emit_sound_at(knifesheathesound, position, 128.);
362
363                 XYZ terrainlight;
364                 terrainlight = terrain.getLighting(position.x, position.z);
365                 if (environment == snowyenvironment) {
366                     if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
367                         Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
368                 } else if (environment == grassyenvironment) {
369                     if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
370                         Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5);
371                 } else if (environment == desertenvironment) {
372                     if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
373                         Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7);
374                 }
375
376                 bloody = 0;
377             } else {
378                 physics = 1;
379                 firstfree = 1;
380                 position -= velocity * multiplier;
381                 tippoint -= velocity * multiplier;
382                 tipvelocity = velocity;
383             }
384         }
385         if (velocity.x != 0 || velocity.z != 0 || velocity.y != 0) {
386             velocity.y += gravity * multiplier;
387
388             XYZ temppoint1, temppoint2;
389             float distance;
390
391             temppoint1 = 0;
392             temppoint2 = velocity;
393             distance = findDistance(&temppoint1, &temppoint2);
394             rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
395             rotation2 *= 360 / 6.28;
396             temppoint1.y = 0;
397             temppoint2.y = 0;
398             rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
399             rotation1 *= 360 / 6.28;
400             rotation3 = 0;
401             smallrotation = 90;
402             smallrotation2 = 0;
403             bigtilt = 0;
404             bigtilt2 = 0;
405             bigrotation = 0;
406             if (temppoint1.x > temppoint2.x)
407                 rotation1 = 360 - rotation1;
408         }
409
410     }
411
412     //Sword physics
413     XYZ mid;
414     XYZ oldmid;
415     XYZ oldmid2;
416
417     tempmult = multiplier;
418     multiplier /= 10;
419     for (int l = 0; l < 10; l++) {
420         if (owner == -1 && (velocity.x || velocity.y || velocity.z) && physics) {
421             //move
422             position += velocity * multiplier;
423             tippoint += tipvelocity * multiplier;
424
425             //Length constrain
426             midp = (position * mass + tippoint * tipmass) / (mass + tipmass);
427             vel = tippoint - midp;
428             Normalise(&vel);
429             newpoint1 = midp - vel * length * (tipmass / (mass + tipmass));
430             newpoint2 = midp + vel * length * (mass / (mass + tipmass));
431             if (!freeze) {
432                 if (freetime > .04) {
433                     velocity = velocity + (newpoint1 - position) / multiplier;
434                     tipvelocity = tipvelocity + (newpoint2 - tippoint) / multiplier;
435                 }
436             }
437             position = newpoint1;
438             tippoint = newpoint2;
439
440
441             //Object collisions
442             whichpatchx = (position.x) / (terrain.size / subdivision * terrain.scale);
443             whichpatchz = (position.z) / (terrain.size / subdivision * terrain.scale);
444             if (whichpatchx > 0 && whichpatchz > 0 && whichpatchx < subdivision && whichpatchz < subdivision) {
445                 for (unsigned int j = 0; j < terrain.patchobjects[whichpatchx][whichpatchz].size(); j++) {
446                     unsigned int k = terrain.patchobjects[whichpatchx][whichpatchz][j];
447
448                     if (firstfree) {
449                         if (type == staff) {
450                             start = tippoint - (position - tippoint) / 5;
451                             end = position + (position - tippoint) / 30;
452                             whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
453                             if (whichhit != -1) {
454                                 XYZ diff;
455                                 diff = (colpoint - position);
456                                 Normalise(&diff);
457                                 hitsomething = 1;
458
459                                 tippoint += (colpoint - position) + diff * .05;
460                                 position = colpoint + diff * .05;
461                                 oldtippoint = tippoint;
462                                 oldposition = tippoint;
463                             }
464                         } else {
465                             start = position - (tippoint - position) / 5;
466                             end = tippoint + (tippoint - position) / 30;
467                             whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
468                             if (whichhit != -1) {
469                                 XYZ diff;
470                                 diff = (colpoint - tippoint);
471                                 Normalise(&diff);
472                                 hitsomething = 1;
473
474                                 position += (colpoint - tippoint) + diff * .05;
475                                 tippoint = colpoint + diff * .05;
476                                 oldposition = position;
477                                 oldtippoint = tippoint;
478                             }
479                         }
480                     }
481
482                     start = oldposition;
483                     end = position;
484                     whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
485                     if (whichhit != -1) {
486                         hitsomething = 1;
487                         position = colpoint;
488                         terrainnormal = DoRotation(Object::objects[k]->model.Triangles[whichhit].facenormal, 0, Object::objects[k]->yaw, 0) * -1;
489                         ReflectVector(&velocity, &terrainnormal);
490                         position += terrainnormal * .002;
491
492                         bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
493                         if (findLengthfast(&velocity) < findLengthfast(&bounceness))
494                             bounceness = 0;
495                         frictionness = abs(normaldotproduct(velocity, terrainnormal));
496                         velocity -= bounceness;
497                         if (1 - friction * frictionness > 0)
498                             velocity *= 1 - friction * frictionness;
499                         else
500                             velocity = 0;
501                         velocity += bounceness * elasticity;
502
503                         if (findLengthfast(&bounceness) > 1) {
504                             int whichsound;
505                             if (type == staff)
506                                 whichsound = footstepsound3 + abs(Random() % 2);
507                             else
508                                 whichsound = clank1sound + abs(Random() % 4);
509                             emit_sound_at(whichsound, position, 128 * findLengthfast(&bounceness));
510                         }
511                     }
512                     start = oldtippoint;
513                     end = tippoint;
514                     whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
515                     if (whichhit != -1) {
516                         hitsomething = 1;
517                         tippoint = colpoint;
518                         terrainnormal = DoRotation(Object::objects[k]->model.Triangles[whichhit].facenormal, 0, Object::objects[k]->yaw, 0) * -1;
519                         ReflectVector(&tipvelocity, &terrainnormal);
520                         tippoint += terrainnormal * .002;
521
522                         bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
523                         if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
524                             bounceness = 0;
525                         frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
526                         tipvelocity -= bounceness;
527                         if (1 - friction * frictionness > 0)
528                             tipvelocity *= 1 - friction * frictionness;
529                         else
530                             tipvelocity = 0;
531                         tipvelocity += bounceness * elasticity;
532
533                         if (findLengthfast(&bounceness) > 1) {
534                             int whichsound;
535                             if (type == staff)
536                                 whichsound = footstepsound3 + abs(Random() % 2);
537                             else
538                                 whichsound = clank1sound + abs(Random() % 4);
539                             emit_sound_at(whichsound, position, 128 * findLengthfast(&bounceness));
540                         }
541                     }
542
543                     if ((Object::objects[k]->type != boxtype && Object::objects[k]->type != platformtype && Object::objects[k]->type != walltype && Object::objects[k]->type != weirdtype) || Object::objects[k]->pitch != 0)
544                         for (int m = 0; m < 2; m++) {
545                             mid = (position * (21 + (float)m * 10) + tippoint * (19 - (float)m * 10)) / 40;
546                             oldmid2 = mid;
547                             oldmid = (oldposition * (21 + (float)m * 10) + oldtippoint * (19 - (float)m * 10)) / 40;
548
549                             start = oldmid;
550                             end = mid;
551                             whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
552                             if (whichhit != -1) {
553                                 hitsomething = 1;
554                                 mid = colpoint;
555                                 terrainnormal = DoRotation(Object::objects[k]->model.Triangles[whichhit].facenormal, 0, Object::objects[k]->yaw, 0) * -1;
556                                 ReflectVector(&velocity, &terrainnormal);
557
558                                 bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
559                                 if (findLengthfast(&velocity) < findLengthfast(&bounceness))
560                                     bounceness = 0;
561                                 frictionness = abs(normaldotproduct(velocity, terrainnormal));
562                                 velocity -= bounceness;
563                                 if (1 - friction * frictionness > 0)
564                                     velocity *= 1 - friction * frictionness;
565                                 else
566                                     velocity = 0;
567                                 velocity += bounceness * elasticity;
568
569                                 if (findLengthfast(&bounceness) > 1) {
570                                     int whichsound;
571                                     if (type == staff)
572                                         whichsound = footstepsound3 + abs(Random() % 2);
573                                     else
574                                         whichsound = clank1sound + abs(Random() % 4);
575                                     emit_sound_at(whichsound, mid, 128 * findLengthfast(&bounceness));
576                                 }
577                                 position += (mid - oldmid2) * (20 / (1 + (float)m * 10));
578                             }
579
580                             mid = (position * (19 - (float)m * 10) + tippoint * (21 + (float)m * 10)) / 40;
581                             oldmid2 = mid;
582                             oldmid = (oldposition * (19 - (float)m * 10) + oldtippoint * (21 + (float)m * 10)) / 40;
583
584                             start = oldmid;
585                             end = mid;
586                             whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
587                             if (whichhit != -1) {
588                                 hitsomething = 1;
589                                 mid = colpoint;
590                                 terrainnormal = DoRotation(Object::objects[k]->model.Triangles[whichhit].facenormal, 0, Object::objects[k]->yaw, 0) * -1;
591                                 ReflectVector(&tipvelocity, &terrainnormal);
592
593                                 bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
594                                 if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
595                                     bounceness = 0;
596                                 frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
597                                 tipvelocity -= bounceness;
598                                 if (1 - friction * frictionness > 0)
599                                     tipvelocity *= 1 - friction * frictionness;
600                                 else
601                                     tipvelocity = 0;
602                                 tipvelocity += bounceness * elasticity;
603
604                                 if (findLengthfast(&bounceness) > 1) {
605                                     int whichsound;
606                                     if (type == staff)
607                                         whichsound = footstepsound3 + abs(Random() % 2);
608                                     else
609                                         whichsound = clank1sound + abs(Random() % 4);
610                                     emit_sound_at(whichsound, mid, 128 * findLengthfast(&bounceness));
611                                 }
612                                 tippoint += (mid - oldmid2) * (20 / (1 + (float)m * 10));
613                             }
614                         }
615                     else {
616                         start = position;
617                         end = tippoint;
618                         whichhit = Object::objects[k]->model.LineCheck(&start, &end, &colpoint, &Object::objects[k]->position, &Object::objects[k]->yaw);
619                         if (whichhit != -1) {
620                             hitsomething = 1;
621                             closestdistance = -1;
622                             closestswordpoint = colpoint;
623                             point[0] = DoRotation(Object::objects[k]->model.getTriangleVertex(whichhit, 0), 0, Object::objects[k]->yaw, 0) + Object::objects[k]->position;
624                             point[1] = DoRotation(Object::objects[k]->model.getTriangleVertex(whichhit, 1), 0, Object::objects[k]->yaw, 0) + Object::objects[k]->position;
625                             point[2] = DoRotation(Object::objects[k]->model.getTriangleVertex(whichhit, 2), 0, Object::objects[k]->yaw, 0) + Object::objects[k]->position;
626                             if (DistancePointLine(&closestswordpoint, &point[0], &point[1], &distance, &colpoint )) {
627                                 if (distance < closestdistance || closestdistance == -1) {
628                                     closestpoint = colpoint;
629                                     closestdistance = distance;
630                                 }
631                             }
632                             if (DistancePointLine(&closestswordpoint, &point[1], &point[2], &distance, &colpoint )) {
633                                 if (distance < closestdistance || closestdistance == -1) {
634                                     closestpoint = colpoint;
635                                     closestdistance = distance;
636                                 }
637                             }
638                             if (DistancePointLine(&closestswordpoint, &point[2], &point[0], &distance, &colpoint )) {
639                                 if (distance < closestdistance || closestdistance == -1) {
640                                     closestpoint = colpoint;
641                                     closestdistance = distance;
642                                 }
643                             }
644                             if (closestdistance != -1 && isnormal(closestdistance)) {
645                                 if (DistancePointLine(&closestpoint, &position, &tippoint, &distance, &colpoint )) {
646                                     closestswordpoint = colpoint;
647                                     velocity += (closestpoint - closestswordpoint);
648                                     tipvelocity += (closestpoint - closestswordpoint);
649                                     position += (closestpoint - closestswordpoint);
650                                     tippoint += (closestpoint - closestswordpoint);
651                                 }
652                             }
653                         }
654                     }
655                 }
656             }
657             //Terrain collisions
658             whichhit = terrain.lineTerrain(oldposition, position, &colpoint);
659             if (whichhit != -1 || position.y < terrain.getHeight(position.x, position.z)) {
660                 hitsomething = 1;
661                 if (whichhit != -1)
662                     position = colpoint * terrain.scale;
663                 else
664                     position.y = terrain.getHeight(position.x, position.z);
665
666                 terrainnormal = terrain.getNormal(position.x, position.z);
667                 ReflectVector(&velocity, &terrainnormal);
668                 position += terrainnormal * .002;
669                 bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
670                 if (findLengthfast(&velocity) < findLengthfast(&bounceness))
671                     bounceness = 0;
672                 frictionness = abs(normaldotproduct(velocity, terrainnormal));
673                 velocity -= bounceness;
674                 if (1 - friction * frictionness > 0)
675                     velocity *= 1 - friction * frictionness;
676                 else
677                     velocity = 0;
678                 if (terrain.getOpacity(position.x, position.z) < .2)
679                     velocity += bounceness * elasticity * .3;
680                 else
681                     velocity += bounceness * elasticity;
682
683                 if (findLengthfast(&bounceness) > 1) {
684                     int whichsound;
685                     if (terrain.getOpacity(position.x, position.z) > .2) {
686                         if (type == staff)
687                             whichsound = footstepsound3 + abs(Random() % 2);
688                         else
689                             whichsound = clank1sound + abs(Random() % 4);
690                     } else {
691                         whichsound = footstepsound + abs(Random() % 2);
692                     }
693                     emit_sound_at(whichsound, position,
694                                   findLengthfast(&bounceness)
695                                   * (terrain.getOpacity(position.x, position.z) > .2 ? 128. : 32.));
696
697                     if (terrain.getOpacity(position.x, position.z) < .2) {
698                         XYZ terrainlight;
699                         terrainlight = terrain.getLighting(position.x, position.z);
700                         if (environment == snowyenvironment) {
701                             if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
702                                 Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
703                         } else if (environment == grassyenvironment) {
704                             if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
705                                 Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5);
706                         } else if (environment == desertenvironment) {
707                             if (distsq(&position, &viewer) < viewdistance * viewdistance / 4)
708                                 Sprite::MakeSprite(cloudsprite, position, velocity, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7);
709                         }
710                     }
711                 }
712             }
713             whichhit = terrain.lineTerrain(oldtippoint, tippoint, &colpoint);
714             if (whichhit != -1 || tippoint.y < terrain.getHeight(tippoint.x, tippoint.z)) {
715                 if (whichhit != -1)
716                     tippoint = colpoint * terrain.scale;
717                 else
718                     tippoint.y = terrain.getHeight(tippoint.x, tippoint.z);
719
720                 terrainnormal = terrain.getNormal(tippoint.x, tippoint.z);
721                 ReflectVector(&tipvelocity, &terrainnormal);
722                 tippoint += terrainnormal * .002;
723                 bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
724                 if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
725                     bounceness = 0;
726                 frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
727                 tipvelocity -= bounceness;
728                 if (1 - friction * frictionness > 0)
729                     tipvelocity *= 1 - friction * frictionness;
730                 else
731                     tipvelocity = 0;
732                 if (terrain.getOpacity(tippoint.x, tippoint.z) < .2)
733                     tipvelocity += bounceness * elasticity * .3;
734                 else
735                     tipvelocity += bounceness * elasticity;
736
737                 if (findLengthfast(&bounceness) > 1) {
738                     int whichsound;
739                     if (terrain.getOpacity(tippoint.x, tippoint.z) > .2) {
740                         if (type == staff)
741                             whichsound = footstepsound3 + abs(Random() % 2);
742                         else
743                             whichsound = clank1sound + abs(Random() % 4);
744                     } else {
745                         whichsound = footstepsound + abs(Random() % 2);
746                     }
747                     emit_sound_at(whichsound, tippoint,
748                                   findLengthfast(&bounceness)
749                                   * (terrain.getOpacity(tippoint.x, tippoint.z) > .2  ? 128. : 32.));
750
751                     if (terrain.getOpacity(tippoint.x, tippoint.z) < .2) {
752                         XYZ terrainlight;
753                         terrainlight = terrain.getLighting(tippoint.x, tippoint.z);
754                         if (environment == snowyenvironment) {
755                             if (distsq(&tippoint, &viewer) < viewdistance * viewdistance / 4)
756                                 Sprite::MakeSprite(cloudsprite, tippoint, tipvelocity, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7);
757                         } else if (environment == grassyenvironment) {
758                             if (distsq(&tippoint, &viewer) < viewdistance * viewdistance / 4)
759                                 Sprite::MakeSprite(cloudsprite, tippoint, tipvelocity, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5);
760                         } else if (environment == desertenvironment) {
761                             if (distsq(&tippoint, &viewer) < viewdistance * viewdistance / 4)
762                                 Sprite::MakeSprite(cloudsprite, tippoint, tipvelocity, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7);
763                         }
764                     }
765                 }
766             }
767
768             //Edges
769             mid = position + tippoint;
770             mid /= 2;
771             mid += (position - mid) / 20;
772             oldmid = mid;
773             if (mid.y < terrain.getHeight(mid.x, mid.z)) {
774                 hitsomething = 1;
775                 mid.y = terrain.getHeight(mid.x, mid.z);
776
777                 terrainnormal = terrain.getNormal(mid.x, mid.z);
778                 ReflectVector(&velocity, &terrainnormal);
779                 //mid+=terrainnormal*.002;
780                 bounceness = terrainnormal * findLength(&velocity) * (abs(normaldotproduct(velocity, terrainnormal)));
781                 if (findLengthfast(&velocity) < findLengthfast(&bounceness))
782                     bounceness = 0;
783                 frictionness = abs(normaldotproduct(velocity, terrainnormal));
784                 velocity -= bounceness;
785                 if (1 - friction * frictionness > 0)
786                     velocity *= 1 - friction * frictionness;
787                 else
788                     velocity = 0;
789                 if (terrain.getOpacity(mid.x, mid.z) < .2)
790                     velocity += bounceness * elasticity * .3;
791                 else
792                     velocity += bounceness * elasticity;
793
794                 if (findLengthfast(&bounceness) > 1) {
795                     int whichsound;
796                     if (terrain.getOpacity(mid.x, mid.z) > .2) {
797                         if (type == staff)
798                             whichsound = footstepsound3 + abs(Random() % 2);
799                         if (type != staff)
800                             whichsound = clank1sound + abs(Random() % 4);
801                     } else {
802                         whichsound = footstepsound + abs(Random() % 2);
803                     }
804                     emit_sound_at(whichsound, mid,
805                                   findLengthfast(&bounceness)
806                                   * (terrain.getOpacity(position.x, position.z) > .2
807                                      ? 128.
808                                      : 32.));
809                 }
810                 position += (mid - oldmid) * 20;
811             }
812
813             mid = position + tippoint;
814             mid /= 2;
815             mid += (tippoint - mid) / 20;
816             oldmid = mid;
817             if (mid.y < terrain.getHeight(mid.x, mid.z)) {
818                 hitsomething = 1;
819                 mid.y = terrain.getHeight(mid.x, mid.z);
820
821                 terrainnormal = terrain.getNormal(mid.x, mid.z);
822                 ReflectVector(&tipvelocity, &terrainnormal);
823                 //mid+=terrainnormal*.002;
824                 bounceness = terrainnormal * findLength(&tipvelocity) * (abs(normaldotproduct(tipvelocity, terrainnormal)));
825                 if (findLengthfast(&tipvelocity) < findLengthfast(&bounceness))
826                     bounceness = 0;
827                 frictionness = abs(normaldotproduct(tipvelocity, terrainnormal));
828                 tipvelocity -= bounceness;
829                 if (1 - friction * frictionness > 0)
830                     tipvelocity *= 1 - friction * frictionness;
831                 else
832                     tipvelocity = 0;
833                 if (terrain.getOpacity(mid.x, mid.z) < .2)
834                     tipvelocity += bounceness * elasticity * .3;
835                 else
836                     tipvelocity += bounceness * elasticity;
837
838                 if (findLengthfast(&bounceness) > 1) {
839                     int whichsound;
840                     if (terrain.getOpacity(mid.x, mid.z) > .2) {
841                         if (type == staff)
842                             whichsound = footstepsound3 + abs(Random() % 2);
843                         if (type != staff)
844                             whichsound = clank1sound + abs(Random() % 4);
845                     } else {
846                         whichsound = footstepsound + abs(Random() % 2);
847                     }
848                     emit_sound_at(whichsound, mid,
849                                   findLengthfast(&bounceness)
850                                   * (terrain.getOpacity(position.x, position.z) > .2
851                                      ? 128.
852                                      : 32.));
853                 }
854                 tippoint += (mid - oldmid) * 20;
855             }
856             //Gravity
857             velocity.y += gravity * multiplier;
858             tipvelocity.y += gravity * multiplier;
859
860             //Rotation
861             XYZ temppoint1, temppoint2;
862             float distance;
863
864             temppoint1 = position;
865             temppoint2 = tippoint;
866             distance = findDistance(&temppoint1, &temppoint2);
867             rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
868             rotation2 *= 360 / 6.28;
869             temppoint1.y = 0;
870             temppoint2.y = 0;
871             rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
872             rotation1 *= 360 / 6.28;
873             rotation3 = 0;
874             smallrotation = 90;
875             smallrotation2 = 0;
876             bigtilt = 0;
877             bigtilt2 = 0;
878             bigrotation = 0;
879             if (temppoint1.x > temppoint2.x)
880                 rotation1 = 360 - rotation1;
881
882             //Stop moving
883             if (findLengthfast(&velocity) < .3 && findLengthfast(&tipvelocity) < .3 && hitsomething) {
884                 freetime += multiplier;
885             }
886
887             if (freetime > .4) {
888                 velocity = 0;
889                 tipvelocity = 0;
890             }
891             firstfree = 0;
892         }
893     }
894     multiplier = tempmult;
895     if (blooddrip && bloody) {
896         blooddripdelay -= blooddrip * multiplier / 2;
897         blooddrip -= multiplier;
898         if (blooddrip < 0)
899             blooddrip = 0;
900         if (blooddrip > 5)
901             blooddrip = 5;
902         if (blooddripdelay < 0 && bloodtoggle) {
903             blooddripdelay = 1;
904             XYZ bloodvel;
905             XYZ bloodloc;
906             bloodloc = position + (tippoint - position) * .7;
907             bloodloc.y -= .05;
908             if (bloodtoggle) {
909                 bloodvel = 0;
910                 Sprite::MakeSprite(bloodsprite, bloodloc, bloodvel, 1, 1, 1, .03, 1);
911             }
912         }
913     }
914     if (onfire) {
915         flamedelay -= multiplier;
916         if (onfire && flamedelay <= 0) {
917             flamedelay = .020;
918             flamedelay -= multiplier;
919             normalrot = 0;
920             if (owner != -1) {
921                 normalrot = Person::players[owner]->velocity;
922             }
923             normalrot.y += 1;
924             if (owner != -1) {
925                 if (Person::players[owner]->onterrain) {
926                     normalrot.y = 1;
927                 }
928             }
929             Sprite::MakeSprite(weaponflamesprite, position + tippoint * (((float)abs(Random() % 100)) / 600 + .05), normalrot, 1, 1, 1, (.6 + (float)abs(Random() % 100) / 200 - .25) * 1 / 3, 1);
930             Sprite::setLastSpriteSpeed(4);
931             Sprite::setLastSpriteAlivetime(.3);
932         }
933     }
934
935     if (!onfire && owner == -1 && type != staff) {
936         flamedelay -= multiplier;
937         if (flamedelay <= 0) {
938             flamedelay = .020;
939             flamedelay -= multiplier;
940             normalrot = 0;
941             if (Random() % 50 == 0 && distsq(&position, &viewer) > 80) {
942                 XYZ shinepoint;
943                 shinepoint = position + (tippoint - position) * (((float)abs(Random() % 100)) / 100);
944                 Sprite::MakeSprite(weaponshinesprite, shinepoint, normalrot, 1, 1, 1, (.1 + (float)abs(Random() % 100) / 200 - .25) * 1 / 3 * fast_sqrt(findDistance(&shinepoint, &viewer)), 1);
945                 Sprite::setLastSpriteSpeed(4);
946                 Sprite::setLastSpriteAlivetime(.3);
947             }
948         }
949     }
950 }
951
952 void Weapons::DoStuff()
953 {
954     //Move
955     int i = 0;
956     for (std::vector<Weapon>::iterator weapon = begin(); weapon != end(); ++weapon) {
957         weapon->doStuff(i++);
958     }
959 }
960
961 void Weapon::draw()
962 {
963     static XYZ terrainlight;
964     static GLfloat M[16];
965
966     if ((frustum.SphereInFrustum(position.x, position.y, position.z, 1) &&
967             distsq(&viewer, &position) < viewdistance * viewdistance)) {
968         bool draw = false;
969         if (owner == -1) {
970             draw = true;
971             if (velocity.x && !physics)
972                 drawhowmany = 10;
973             else
974                 drawhowmany = 1;
975         } else {
976             if (Person::players[owner]->occluded < 25)
977                 if ((frustum.SphereInFrustum(Person::players[owner]->coords.x, Person::players[owner]->coords.y + Person::players[owner]->scale * 3, Person::players[owner]->coords.z, Person::players[owner]->scale * 8) && distsq(&viewer, &Person::players[owner]->coords) < viewdistance * viewdistance) || Person::players[owner]->skeleton.free == 3)
978                     draw = true;
979             if (
980                 (Person::players[owner]->animTarget == knifeslashstartanim ||
981                  Person::players[owner]->animTarget == swordsneakattackanim ||
982                  (Person::players[owner]->animCurrent == staffhitanim && Person::players[owner]->frameCurrent > 1) ||
983                  (Person::players[owner]->animCurrent == staffhitreversedanim && Person::players[owner]->frameCurrent > 1) ||
984                  (Person::players[owner]->animCurrent == staffspinhitanim && Person::players[owner]->frameCurrent > 1) ||
985                  (Person::players[owner]->animCurrent == staffspinhitreversedanim && Person::players[owner]->frameCurrent > 1) ||
986                  (Person::players[owner]->animCurrent == staffgroundsmashanim && Person::players[owner]->frameCurrent > 1) ||
987                  (Person::players[owner]->animTarget == swordslashanim && Person::players[owner]->frameTarget < 7) ||
988                  Person::players[owner]->animTarget == crouchstabanim ||
989                  Person::players[owner]->animTarget == swordslashreversalanim ||
990                  Person::players[owner]->animTarget == swordslashreversedanim ||
991                  Person::players[owner]->animTarget == knifefollowanim ||
992                  Person::players[owner]->animTarget == swordgroundstabanim ||
993                  Person::players[owner]->animTarget == knifethrowanim) &&
994                 Person::players[owner]->animTarget == lastdrawnanim &&
995                 !Person::players[owner]->skeleton.free
996             ) {
997                 drawhowmany = 10;
998             } else {
999                 drawhowmany = 1;
1000             }
1001             if (Person::players[owner]->animTarget == swordgroundstabanim) {
1002                 lastdrawnrotation1 = rotation1;
1003                 lastdrawnrotation2 = rotation2;
1004                 lastdrawnrotation3 = rotation3;
1005                 lastdrawnbigrotation = bigrotation;
1006                 lastdrawnbigtilt = bigtilt;
1007                 lastdrawnbigtilt2 = bigtilt2;
1008                 lastdrawnsmallrotation = smallrotation;
1009                 lastdrawnsmallrotation2 = smallrotation2;
1010             }
1011         }
1012         if (draw) {
1013             terrainlight = terrain.getLighting(position.x, position.z);
1014             if (drawhowmany > 0) {
1015                 glAlphaFunc(GL_GREATER, 0.01);
1016             }
1017             for (int j = drawhowmany; j > 0; j--) {
1018                 glMatrixMode(GL_MODELVIEW);
1019                 glPushMatrix();
1020                 glColor4f(terrainlight.x, terrainlight.y, terrainlight.z, j / drawhowmany);
1021                 if (owner == -1)
1022                     glTranslatef(position.x * (((float)(j)) / drawhowmany) + lastdrawnposition.x * (1 - ((float)(j)) / drawhowmany), position.y * (((float)(j)) / drawhowmany) + lastdrawnposition.y * (1 - ((float)(j)) / drawhowmany), position.z * (((float)(j)) / drawhowmany) + lastdrawnposition.z * (1 - ((float)(j)) / drawhowmany));
1023                 else
1024                     glTranslatef(position.x * (((float)(j)) / drawhowmany) + lastdrawnposition.x * (1 - ((float)(j)) / drawhowmany), position.y * (((float)(j)) / drawhowmany) - .02 + lastdrawnposition.y * (1 - ((float)(j)) / drawhowmany), position.z * (((float)(j)) / drawhowmany) + lastdrawnposition.z * (1 - ((float)(j)) / drawhowmany));
1025                 glRotatef(bigrotation * (((float)(j)) / drawhowmany) + lastdrawnbigrotation * (1 - ((float)(j)) / drawhowmany), 0, 1, 0);
1026                 glRotatef(bigtilt2 * (((float)(j)) / drawhowmany) + lastdrawnbigtilt2 * (1 - ((float)(j)) / drawhowmany), 1, 0, 0);
1027                 glRotatef(bigtilt * (((float)(j)) / drawhowmany) + lastdrawnbigtilt * (1 - ((float)(j)) / drawhowmany), 0, 0, 1);
1028                 glRotatef(-rotation1 * (((float)(j)) / drawhowmany) - lastdrawnrotation1 * (1 - ((float)(j)) / drawhowmany) + 90, 0, 1, 0);
1029                 glRotatef(-rotation2 * (((float)(j)) / drawhowmany) - lastdrawnrotation2 * (1 - ((float)(j)) / drawhowmany) + 90, 0, 0, 1);
1030                 glRotatef(-rotation3 * (((float)(j)) / drawhowmany) - lastdrawnrotation3 * (1 - ((float)(j)) / drawhowmany), 0, 1, 0);
1031                 glRotatef(smallrotation * (((float)(j)) / drawhowmany) + lastdrawnsmallrotation * (1 - ((float)(j)) / drawhowmany), 1, 0, 0);
1032                 glRotatef(smallrotation2 * (((float)(j)) / drawhowmany) + lastdrawnsmallrotation2 * (1 - ((float)(j)) / drawhowmany), 0, 1, 0);
1033
1034                 if (owner != -1) {
1035                     if (Person::players[owner]->animTarget == staffhitanim || Person::players[owner]->animCurrent == staffhitanim || Person::players[owner]->animTarget == staffhitreversedanim || Person::players[owner]->animCurrent == staffhitreversedanim) {
1036                         glTranslatef(0, 0, -.3);
1037                     }
1038                     if (Person::players[owner]->animTarget == staffgroundsmashanim || Person::players[owner]->animCurrent == staffgroundsmashanim || Person::players[owner]->animTarget == staffspinhitreversedanim || Person::players[owner]->animCurrent == staffspinhitreversedanim || Person::players[owner]->animTarget == staffspinhitanim || Person::players[owner]->animCurrent == staffspinhitanim) {
1039                         glTranslatef(0, 0, -.1);
1040                     }
1041                 }
1042
1043                 glEnable(GL_LIGHTING);
1044                 switch (type) {
1045                 case knife:
1046                     if (!bloody || !bloodtoggle)
1047                         throwingknifemodel.drawdifftex(knifetextureptr);
1048                     if (bloodtoggle) {
1049                         if (bloody == 1)
1050                             throwingknifemodel.drawdifftex(lightbloodknifetextureptr);
1051                         if (bloody == 2)
1052                             throwingknifemodel.drawdifftex(bloodknifetextureptr);
1053                     }
1054                     break;
1055                 case sword:
1056                     if (!bloody || !bloodtoggle)
1057                         swordmodel.drawdifftex(swordtextureptr);
1058                     if (bloodtoggle) {
1059                         if (bloody == 1)
1060                             swordmodel.drawdifftex(lightbloodswordtextureptr);
1061                         if (bloody == 2)
1062                             swordmodel.drawdifftex(bloodswordtextureptr);
1063                     }
1064                     break;
1065                 case staff:
1066                     staffmodel.drawdifftex(stafftextureptr);
1067                     break;
1068                 }
1069
1070                 glPopMatrix();
1071             }
1072
1073             lastdrawnposition = position;
1074             lastdrawntippoint = tippoint;
1075             lastdrawnrotation1 = rotation1;
1076             lastdrawnrotation2 = rotation2;
1077             lastdrawnrotation3 = rotation3;
1078             lastdrawnbigrotation = bigrotation;
1079             lastdrawnbigtilt = bigtilt;
1080             lastdrawnbigtilt2 = bigtilt2;
1081             lastdrawnsmallrotation = smallrotation;
1082             lastdrawnsmallrotation2 = smallrotation2;
1083             if (owner != -1)
1084                 lastdrawnanim = Person::players[owner]->animCurrent;
1085         }
1086         if (owner != -1) {
1087             glMatrixMode(GL_MODELVIEW);
1088             glPushMatrix();
1089             glLoadIdentity();
1090             glTranslatef(position.x, position.y - .02, position.z);
1091             glRotatef(bigrotation, 0, 1, 0);
1092             glRotatef(bigtilt2, 1, 0, 0);
1093             glRotatef(bigtilt, 0, 0, 1);
1094             glRotatef(-rotation1 + 90, 0, 1, 0);
1095             glRotatef(-rotation2 + 90, 0, 0, 1);
1096             glRotatef(-rotation3, 0, 1, 0);
1097             glRotatef(smallrotation, 1, 0, 0);
1098             glRotatef(smallrotation2, 0, 1, 0);
1099             glTranslatef(0, 0, length);
1100             glGetFloatv(GL_MODELVIEW_MATRIX, M);
1101             tippoint.x = M[12];
1102             tippoint.y = M[13];
1103             tippoint.z = M[14];
1104             glPopMatrix();
1105         }
1106     }
1107 }
1108
1109 void Weapon::drop(XYZ v, XYZ tv, bool sethitsomething)
1110 {
1111     owner = -1;
1112     velocity = v;
1113     tipvelocity = tv;
1114     missed = 1;
1115     if (sethitsomething) {
1116         hitsomething = 0;
1117     }
1118     freetime = 0;
1119     firstfree = 1;
1120     physics = 1;
1121 }
1122
1123 void Weapon::thrown(XYZ v, bool sethitsomething)
1124 {
1125     drop(v, v, sethitsomething);
1126     missed = 0;
1127     physics = 0;
1128 }
1129
1130 int Weapons::Draw()
1131 {
1132     glAlphaFunc(GL_GREATER, 0.9);
1133     glEnable(GL_TEXTURE_2D);
1134     glEnable(GL_BLEND);
1135     glEnable(GL_CULL_FACE);
1136     glCullFace(GL_FRONT);
1137     glDepthMask(1);
1138
1139     for (std::vector<Weapon>::iterator weapon = begin(); weapon != end(); ++weapon) {
1140         weapon->draw();
1141     }
1142     return 0;
1143 }
1144
1145 Weapons::Weapons()
1146 {
1147 }