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