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