]> git.lizzy.rs Git - minetest.git/blob - src/content_sao.cpp
+ fireflies
[minetest.git] / src / content_sao.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "content_sao.h"
21 #include "collision.h"
22 #include "environment.h"
23
24 core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
25
26 /*
27         TestSAO
28 */
29
30 // Prototype
31 TestSAO proto_TestSAO(NULL, 0, v3f(0,0,0));
32
33 TestSAO::TestSAO(ServerEnvironment *env, u16 id, v3f pos):
34         ServerActiveObject(env, id, pos),
35         m_timer1(0),
36         m_age(0)
37 {
38         ServerActiveObject::registerType(getType(), create);
39 }
40
41 ServerActiveObject* TestSAO::create(ServerEnvironment *env, u16 id, v3f pos,
42                 const std::string &data)
43 {
44         return new TestSAO(env, id, pos);
45 }
46
47 void TestSAO::step(float dtime, bool send_recommended)
48 {
49         m_age += dtime;
50         if(m_age > 10)
51         {
52                 m_removed = true;
53                 return;
54         }
55
56         m_base_position.Y += dtime * BS * 2;
57         if(m_base_position.Y > 8*BS)
58                 m_base_position.Y = 2*BS;
59
60         if(send_recommended == false)
61                 return;
62
63         m_timer1 -= dtime;
64         if(m_timer1 < 0.0)
65         {
66                 m_timer1 += 0.125;
67                 //dstream<<"TestSAO: id="<<getId()<<" sending data"<<std::endl;
68
69                 std::string data;
70
71                 data += itos(0); // 0 = position
72                 data += " ";
73                 data += itos(m_base_position.X);
74                 data += " ";
75                 data += itos(m_base_position.Y);
76                 data += " ";
77                 data += itos(m_base_position.Z);
78
79                 ActiveObjectMessage aom(getId(), false, data);
80                 m_messages_out.push_back(aom);
81         }
82 }
83
84
85 /*
86         ItemSAO
87 */
88
89 // Prototype
90 ItemSAO proto_ItemSAO(NULL, 0, v3f(0,0,0), "");
91
92 ItemSAO::ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
93                 const std::string inventorystring):
94         ServerActiveObject(env, id, pos),
95         m_inventorystring(inventorystring),
96         m_speed_f(0,0,0),
97         m_last_sent_position(0,0,0)
98 {
99         ServerActiveObject::registerType(getType(), create);
100 }
101
102 ServerActiveObject* ItemSAO::create(ServerEnvironment *env, u16 id, v3f pos,
103                 const std::string &data)
104 {
105         std::istringstream is(data, std::ios::binary);
106         char buf[1];
107         // read version
108         is.read(buf, 1);
109         u8 version = buf[0];
110         // check if version is supported
111         if(version != 0)
112                 return NULL;
113         std::string inventorystring = deSerializeString(is);
114         dstream<<"ItemSAO::create(): Creating item \""
115                         <<inventorystring<<"\""<<std::endl;
116         return new ItemSAO(env, id, pos, inventorystring);
117 }
118
119 void ItemSAO::step(float dtime, bool send_recommended)
120 {
121         assert(m_env);
122
123         const float interval = 0.2;
124         if(m_move_interval.step(dtime, interval)==false)
125                 return;
126         dtime = interval;
127         
128         core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
129         collisionMoveResult moveresult;
130         // Apply gravity
131         m_speed_f += v3f(0, -dtime*9.81*BS, 0);
132         // Maximum movement without glitches
133         f32 pos_max_d = BS*0.25;
134         // Limit speed
135         if(m_speed_f.getLength()*dtime > pos_max_d)
136                 m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
137         v3f pos_f = getBasePosition();
138         v3f pos_f_old = pos_f;
139         moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
140                         box, dtime, pos_f, m_speed_f);
141         
142         if(send_recommended == false)
143                 return;
144
145         if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
146         {
147                 setBasePosition(pos_f);
148                 m_last_sent_position = pos_f;
149
150                 std::ostringstream os(std::ios::binary);
151                 char buf[6];
152                 // command (0 = update position)
153                 buf[0] = 0;
154                 os.write(buf, 1);
155                 // pos
156                 writeS32((u8*)buf, m_base_position.X*1000);
157                 os.write(buf, 4);
158                 writeS32((u8*)buf, m_base_position.Y*1000);
159                 os.write(buf, 4);
160                 writeS32((u8*)buf, m_base_position.Z*1000);
161                 os.write(buf, 4);
162                 // create message and add to list
163                 ActiveObjectMessage aom(getId(), false, os.str());
164                 m_messages_out.push_back(aom);
165         }
166 }
167
168 std::string ItemSAO::getClientInitializationData()
169 {
170         std::ostringstream os(std::ios::binary);
171         char buf[6];
172         // version
173         buf[0] = 0;
174         os.write(buf, 1);
175         // pos
176         writeS32((u8*)buf, m_base_position.X*1000);
177         os.write(buf, 4);
178         writeS32((u8*)buf, m_base_position.Y*1000);
179         os.write(buf, 4);
180         writeS32((u8*)buf, m_base_position.Z*1000);
181         os.write(buf, 4);
182         // inventorystring
183         os<<serializeString(m_inventorystring);
184         return os.str();
185 }
186
187 std::string ItemSAO::getStaticData()
188 {
189         dstream<<__FUNCTION_NAME<<std::endl;
190         std::ostringstream os(std::ios::binary);
191         char buf[1];
192         // version
193         buf[0] = 0;
194         os.write(buf, 1);
195         // inventorystring
196         os<<serializeString(m_inventorystring);
197         return os.str();
198 }
199
200 InventoryItem * ItemSAO::createInventoryItem()
201 {
202         try{
203                 std::istringstream is(m_inventorystring, std::ios_base::binary);
204                 InventoryItem *item = InventoryItem::deSerialize(is);
205                 dstream<<__FUNCTION_NAME<<": m_inventorystring=\""
206                                 <<m_inventorystring<<"\" -> item="<<item
207                                 <<std::endl;
208                 return item;
209         }
210         catch(SerializationError &e)
211         {
212                 dstream<<__FUNCTION_NAME<<": serialization error: "
213                                 <<"m_inventorystring=\""<<m_inventorystring<<"\""<<std::endl;
214                 return NULL;
215         }
216 }
217
218
219 /*
220         RatSAO
221 */
222
223 // Prototype
224 RatSAO proto_RatSAO(NULL, 0, v3f(0,0,0));
225
226 RatSAO::RatSAO(ServerEnvironment *env, u16 id, v3f pos):
227         ServerActiveObject(env, id, pos),
228         m_is_active(false),
229         m_speed_f(0,0,0)
230 {
231         ServerActiveObject::registerType(getType(), create);
232
233         m_oldpos = v3f(0,0,0);
234         m_last_sent_position = v3f(0,0,0);
235         m_yaw = 0;
236         m_counter1 = 0;
237         m_counter2 = 0;
238         m_age = 0;
239         m_touching_ground = false;
240 }
241
242 ServerActiveObject* RatSAO::create(ServerEnvironment *env, u16 id, v3f pos,
243                 const std::string &data)
244 {
245         std::istringstream is(data, std::ios::binary);
246         char buf[1];
247         // read version
248         is.read(buf, 1);
249         u8 version = buf[0];
250         // check if version is supported
251         if(version != 0)
252                 return NULL;
253         return new RatSAO(env, id, pos);
254 }
255
256 void RatSAO::step(float dtime, bool send_recommended)
257 {
258         assert(m_env);
259
260         if(m_is_active == false)
261         {
262                 if(m_inactive_interval.step(dtime, 0.5)==false)
263                         return;
264         }
265
266         /*
267                 The AI
268         */
269
270         /*m_age += dtime;
271         if(m_age > 60)
272         {
273                 // Die
274                 m_removed = true;
275                 return;
276         }*/
277
278         // Apply gravity
279         m_speed_f.Y -= dtime*9.81*BS;
280
281         /*
282                 Move around if some player is close
283         */
284         bool player_is_close = false;
285         // Check connected players
286         core::list<Player*> players = m_env->getPlayers(true);
287         core::list<Player*>::Iterator i;
288         for(i = players.begin();
289                         i != players.end(); i++)
290         {
291                 Player *player = *i;
292                 v3f playerpos = player->getPosition();
293                 if(m_base_position.getDistanceFrom(playerpos) < BS*10.0)
294                 {
295                         player_is_close = true;
296                         break;
297                 }
298         }
299
300         m_is_active = player_is_close;
301         
302         if(player_is_close == false)
303         {
304                 m_speed_f.X = 0;
305                 m_speed_f.Z = 0;
306         }
307         else
308         {
309                 // Move around
310                 v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
311                 f32 speed = 2*BS;
312                 m_speed_f.X = speed * dir.X;
313                 m_speed_f.Z = speed * dir.Z;
314
315                 if(m_touching_ground && (m_oldpos - m_base_position).getLength()
316                                 < dtime*speed/2)
317                 {
318                         m_counter1 -= dtime;
319                         if(m_counter1 < 0.0)
320                         {
321                                 m_counter1 += 1.0;
322                                 m_speed_f.Y = 5.0*BS;
323                         }
324                 }
325
326                 {
327                         m_counter2 -= dtime;
328                         if(m_counter2 < 0.0)
329                         {
330                                 m_counter2 += (float)(myrand()%100)/100*3.0;
331                                 m_yaw += ((float)(myrand()%200)-100)/100*180;
332                                 m_yaw = wrapDegrees(m_yaw);
333                         }
334                 }
335         }
336         
337         m_oldpos = m_base_position;
338
339         /*
340                 Move it, with collision detection
341         */
342
343         core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
344         collisionMoveResult moveresult;
345         // Maximum movement without glitches
346         f32 pos_max_d = BS*0.25;
347         // Limit speed
348         if(m_speed_f.getLength()*dtime > pos_max_d)
349                 m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
350         v3f pos_f = getBasePosition();
351         v3f pos_f_old = pos_f;
352         moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
353                         box, dtime, pos_f, m_speed_f);
354         m_touching_ground = moveresult.touching_ground;
355         
356         setBasePosition(pos_f);
357
358         if(send_recommended == false)
359                 return;
360
361         if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
362         {
363                 m_last_sent_position = pos_f;
364
365                 std::ostringstream os(std::ios::binary);
366                 // command (0 = update position)
367                 writeU8(os, 0);
368                 // pos
369                 writeV3F1000(os, m_base_position);
370                 // yaw
371                 writeF1000(os, m_yaw);
372                 // create message and add to list
373                 ActiveObjectMessage aom(getId(), false, os.str());
374                 m_messages_out.push_back(aom);
375         }
376 }
377
378 std::string RatSAO::getClientInitializationData()
379 {
380         std::ostringstream os(std::ios::binary);
381         // version
382         writeU8(os, 0);
383         // pos
384         writeV3F1000(os, m_base_position);
385         return os.str();
386 }
387
388 std::string RatSAO::getStaticData()
389 {
390         //dstream<<__FUNCTION_NAME<<std::endl;
391         std::ostringstream os(std::ios::binary);
392         // version
393         writeU8(os, 0);
394         return os.str();
395 }
396
397 InventoryItem* RatSAO::createPickedUpItem()
398 {
399         std::istringstream is("CraftItem rat 1", std::ios_base::binary);
400         InventoryItem *item = InventoryItem::deSerialize(is);
401         return item;
402 }
403
404 /*
405         Oerkki1SAO
406 */
407
408 // Y is copied, X and Z change is limited
409 void accelerate_xz(v3f &speed, v3f target_speed, f32 max_increase)
410 {
411         v3f d_wanted = target_speed - speed;
412         d_wanted.Y = 0;
413         f32 dl_wanted = d_wanted.getLength();
414         f32 dl = dl_wanted;
415         if(dl > max_increase)
416                 dl = max_increase;
417         
418         v3f d = d_wanted.normalize() * dl;
419
420         speed.X += d.X;
421         speed.Z += d.Z;
422         speed.Y = target_speed.Y;
423 }
424
425 // Prototype
426 Oerkki1SAO proto_Oerkki1SAO(NULL, 0, v3f(0,0,0));
427
428 Oerkki1SAO::Oerkki1SAO(ServerEnvironment *env, u16 id, v3f pos):
429         ServerActiveObject(env, id, pos),
430         m_is_active(false),
431         m_speed_f(0,0,0)
432 {
433         ServerActiveObject::registerType(getType(), create);
434
435         m_oldpos = v3f(0,0,0);
436         m_last_sent_position = v3f(0,0,0);
437         m_yaw = 0;
438         m_counter1 = 0;
439         m_counter2 = 0;
440         m_age = 0;
441         m_touching_ground = false;
442         m_hp = 20;
443         m_after_jump_timer = 0;
444 }
445
446 ServerActiveObject* Oerkki1SAO::create(ServerEnvironment *env, u16 id, v3f pos,
447                 const std::string &data)
448 {
449         std::istringstream is(data, std::ios::binary);
450         // read version
451         u8 version = readU8(is);
452         // read hp
453         u8 hp = readU8(is);
454         // check if version is supported
455         if(version != 0)
456                 return NULL;
457         Oerkki1SAO *o = new Oerkki1SAO(env, id, pos);
458         o->m_hp = hp;
459         return o;
460 }
461
462 void Oerkki1SAO::step(float dtime, bool send_recommended)
463 {
464         assert(m_env);
465
466         if(m_is_active == false)
467         {
468                 if(m_inactive_interval.step(dtime, 0.5)==false)
469                         return;
470         }
471
472         /*
473                 The AI
474         */
475
476         m_age += dtime;
477         if(m_age > 120)
478         {
479                 // Die
480                 m_removed = true;
481                 return;
482         }
483
484         m_after_jump_timer -= dtime;
485
486         v3f old_speed = m_speed_f;
487
488         // Apply gravity
489         m_speed_f.Y -= dtime*9.81*BS;
490
491         /*
492                 Move around if some player is close
493         */
494         bool player_is_close = false;
495         bool player_is_too_close = false;
496         v3f near_player_pos;
497         // Check connected players
498         core::list<Player*> players = m_env->getPlayers(true);
499         core::list<Player*>::Iterator i;
500         for(i = players.begin();
501                         i != players.end(); i++)
502         {
503                 Player *player = *i;
504                 v3f playerpos = player->getPosition();
505                 f32 dist = m_base_position.getDistanceFrom(playerpos);
506                 if(dist < BS*1.45)
507                 {
508                         player_is_too_close = true;
509                         near_player_pos = playerpos;
510                         break;
511                 }
512                 else if(dist < BS*15.0)
513                 {
514                         player_is_close = true;
515                         near_player_pos = playerpos;
516                 }
517         }
518
519         m_is_active = player_is_close;
520
521         v3f target_speed = m_speed_f;
522
523         if(!player_is_close)
524         {
525                 target_speed = v3f(0,0,0);
526         }
527         else
528         {
529                 // Move around
530
531                 v3f ndir = near_player_pos - m_base_position;
532                 ndir.Y = 0;
533                 ndir.normalize();
534
535                 f32 nyaw = 180./PI*atan2(ndir.Z,ndir.X);
536                 if(nyaw < m_yaw - 180)
537                         nyaw += 360;
538                 else if(nyaw > m_yaw + 180)
539                         nyaw -= 360;
540                 m_yaw = 0.95*m_yaw + 0.05*nyaw;
541                 m_yaw = wrapDegrees(m_yaw);
542                 
543                 f32 speed = 2*BS;
544
545                 if((m_touching_ground || m_after_jump_timer > 0.0)
546                                 && !player_is_too_close)
547                 {
548                         v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
549                         target_speed.X = speed * dir.X;
550                         target_speed.Z = speed * dir.Z;
551                 }
552
553                 if(m_touching_ground && (m_oldpos - m_base_position).getLength()
554                                 < dtime*speed/2)
555                 {
556                         m_counter1 -= dtime;
557                         if(m_counter1 < 0.0)
558                         {
559                                 m_counter1 += 0.2;
560                                 // Jump
561                                 target_speed.Y = 5.0*BS;
562                                 m_after_jump_timer = 1.0;
563                         }
564                 }
565
566                 {
567                         m_counter2 -= dtime;
568                         if(m_counter2 < 0.0)
569                         {
570                                 m_counter2 += (float)(myrand()%100)/100*3.0;
571                                 //m_yaw += ((float)(myrand()%200)-100)/100*180;
572                                 m_yaw += ((float)(myrand()%200)-100)/100*90;
573                                 m_yaw = wrapDegrees(m_yaw);
574                         }
575                 }
576         }
577         
578         if((m_speed_f - target_speed).getLength() > BS*4 || player_is_too_close)
579                 accelerate_xz(m_speed_f, target_speed, dtime*BS*8);
580         else
581                 accelerate_xz(m_speed_f, target_speed, dtime*BS*4);
582         
583         m_oldpos = m_base_position;
584
585         /*
586                 Move it, with collision detection
587         */
588
589         core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*5./3.,BS/3.);
590         collisionMoveResult moveresult;
591         // Maximum movement without glitches
592         f32 pos_max_d = BS*0.25;
593         /*// Limit speed
594         if(m_speed_f.getLength()*dtime > pos_max_d)
595                 m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);*/
596         v3f pos_f = getBasePosition();
597         v3f pos_f_old = pos_f;
598         moveresult = collisionMovePrecise(&m_env->getMap(), pos_max_d,
599                         box, dtime, pos_f, m_speed_f);
600         m_touching_ground = moveresult.touching_ground;
601         
602         // Do collision damage
603         float tolerance = BS*12;
604         float factor = BS*0.5;
605         v3f speed_diff = old_speed - m_speed_f;
606         // Increase effect in X and Z
607         speed_diff.X *= 2;
608         speed_diff.Z *= 2;
609         float vel = speed_diff.getLength();
610         if(vel > tolerance)
611         {
612                 f32 damage_f = (vel - tolerance)/BS*factor;
613                 u16 damage = (u16)(damage_f+0.5);
614                 doDamage(damage);
615         }
616
617         setBasePosition(pos_f);
618
619         if(send_recommended == false && m_speed_f.getLength() < 3.0*BS)
620                 return;
621
622         if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
623         {
624                 m_last_sent_position = pos_f;
625
626                 std::ostringstream os(std::ios::binary);
627                 // command (0 = update position)
628                 writeU8(os, 0);
629                 // pos
630                 writeV3F1000(os, m_base_position);
631                 // yaw
632                 writeF1000(os, m_yaw);
633                 // create message and add to list
634                 ActiveObjectMessage aom(getId(), false, os.str());
635                 m_messages_out.push_back(aom);
636         }
637 }
638
639 std::string Oerkki1SAO::getClientInitializationData()
640 {
641         std::ostringstream os(std::ios::binary);
642         // version
643         writeU8(os, 0);
644         // pos
645         writeV3F1000(os, m_base_position);
646         return os.str();
647 }
648
649 std::string Oerkki1SAO::getStaticData()
650 {
651         //dstream<<__FUNCTION_NAME<<std::endl;
652         std::ostringstream os(std::ios::binary);
653         // version
654         writeU8(os, 0);
655         // hp
656         writeU8(os, m_hp);
657         return os.str();
658 }
659
660 u16 Oerkki1SAO::punch(const std::string &toolname, v3f dir)
661 {
662         m_speed_f += dir*12*BS;
663
664         u16 amount = 5;
665         doDamage(amount);
666         return 65536/100;
667 }
668
669 void Oerkki1SAO::doDamage(u16 d)
670 {
671         dstream<<"oerkki damage: "<<d<<std::endl;
672         
673         if(d < m_hp)
674         {
675                 m_hp -= d;
676         }
677         else
678         {
679                 // Die
680                 m_hp = 0;
681                 m_removed = true;
682         }
683
684         {
685                 std::ostringstream os(std::ios::binary);
686                 // command (1 = damage)
687                 writeU8(os, 1);
688                 // amount
689                 writeU8(os, d);
690                 // create message and add to list
691                 ActiveObjectMessage aom(getId(), false, os.str());
692                 m_messages_out.push_back(aom);
693         }
694 }
695
696 /*
697         FireflySAO
698 */
699
700 // Prototype
701 FireflySAO proto_FireflySAO(NULL, 0, v3f(0,0,0));
702
703 FireflySAO::FireflySAO(ServerEnvironment *env, u16 id, v3f pos):
704         ServerActiveObject(env, id, pos),
705         m_is_active(false),
706         m_speed_f(0,0,0)
707 {
708         ServerActiveObject::registerType(getType(), create);
709
710         m_oldpos = v3f(0,0,0);
711         m_last_sent_position = v3f(0,0,0);
712         m_yaw = 0;
713         m_counter1 = 0;
714         m_counter2 = 0;
715         m_age = 0;
716         m_touching_ground = false;
717 }
718
719 ServerActiveObject* FireflySAO::create(ServerEnvironment *env, u16 id, v3f pos,
720                 const std::string &data)
721 {
722         std::istringstream is(data, std::ios::binary);
723         char buf[1];
724         // read version
725         is.read(buf, 1);
726         u8 version = buf[0];
727         // check if version is supported
728         if(version != 0)
729                 return NULL;
730         return new FireflySAO(env, id, pos);
731 }
732
733 void FireflySAO::step(float dtime, bool send_recommended)
734 {
735         assert(m_env);
736
737         if(m_is_active == false)
738         {
739                 if(m_inactive_interval.step(dtime, 0.5)==false)
740                         return;
741         }
742
743         /*
744                 The AI
745         */
746
747         // Apply (less) gravity
748         m_speed_f.Y -= dtime*3*BS;
749
750         /*
751                 Move around if some player is close
752         */
753         bool player_is_close = false;
754         // Check connected players
755         core::list<Player*> players = m_env->getPlayers(true);
756         core::list<Player*>::Iterator i;
757         for(i = players.begin();
758                         i != players.end(); i++)
759         {
760                 Player *player = *i;
761                 v3f playerpos = player->getPosition();
762                 if(m_base_position.getDistanceFrom(playerpos) < BS*10.0)
763                 {
764                         player_is_close = true;
765                         break;
766                 }
767         }
768
769         m_is_active = player_is_close;
770         
771         if(player_is_close == false)
772         {
773                 m_speed_f.X = 0;
774                 m_speed_f.Z = 0;
775         }
776         else
777         {
778                 // Move around
779                 v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
780                 f32 speed = BS/2;
781                 m_speed_f.X = speed * dir.X;
782                 m_speed_f.Z = speed * dir.Z;
783
784                 if(m_touching_ground && (m_oldpos - m_base_position).getLength()
785                                 < dtime*speed/2)
786                 {
787                         m_counter1 -= dtime;
788                         if(m_counter1 < 0.0)
789                         {
790                                 m_counter1 += 1.0;
791                                 m_speed_f.Y = 5.0*BS;
792                         }
793                 }
794
795                 {
796                         m_counter2 -= dtime;
797                         if(m_counter2 < 0.0)
798                         {
799                                 m_counter2 += (float)(myrand()%100)/100*3.0;
800                                 m_yaw += ((float)(myrand()%200)-100)/100*180;
801                                 m_yaw = wrapDegrees(m_yaw);
802                         }
803                 }
804         }
805         
806         m_oldpos = m_base_position;
807
808         /*
809                 Move it, with collision detection
810         */
811
812         core::aabbox3d<f32> box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.);
813         collisionMoveResult moveresult;
814         // Maximum movement without glitches
815         f32 pos_max_d = BS*0.25;
816         // Limit speed
817         if(m_speed_f.getLength()*dtime > pos_max_d)
818                 m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
819         v3f pos_f = getBasePosition();
820         v3f pos_f_old = pos_f;
821         moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
822                         box, dtime, pos_f, m_speed_f);
823         m_touching_ground = moveresult.touching_ground;
824         
825         setBasePosition(pos_f);
826
827         if(send_recommended == false)
828                 return;
829
830         if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
831         {
832                 m_last_sent_position = pos_f;
833
834                 std::ostringstream os(std::ios::binary);
835                 // command (0 = update position)
836                 writeU8(os, 0);
837                 // pos
838                 writeV3F1000(os, m_base_position);
839                 // yaw
840                 writeF1000(os, m_yaw);
841                 // create message and add to list
842                 ActiveObjectMessage aom(getId(), false, os.str());
843                 m_messages_out.push_back(aom);
844         }
845 }
846
847 std::string FireflySAO::getClientInitializationData()
848 {
849         std::ostringstream os(std::ios::binary);
850         // version
851         writeU8(os, 0);
852         // pos
853         writeV3F1000(os, m_base_position);
854         return os.str();
855 }
856
857 std::string FireflySAO::getStaticData()
858 {
859         //dstream<<__FUNCTION_NAME<<std::endl;
860         std::ostringstream os(std::ios::binary);
861         // version
862         writeU8(os, 0);
863         return os.str();
864 }
865
866 InventoryItem* FireflySAO::createPickedUpItem()
867 {
868         std::istringstream is("CraftItem firefly 1", std::ios_base::binary);
869         InventoryItem *item = InventoryItem::deSerialize(is);
870         return item;
871 }