Linux multi-monitor fullscreen support
[ryzomcore.git] / snowballs2 / client / src / entities.cpp
blob3b2d23dcd7060b4f09a968a7255f628a088cffe0
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 // Includes
24 #include <nel/misc/types_nl.h>
26 #include <cmath>
27 #include <map>
29 #include <nel/misc/types_nl.h>
30 #include <nel/misc/event_listener.h>
31 #include <nel/misc/command.h>
32 #include <nel/misc/log.h>
33 #include <nel/misc/time_nl.h>
34 #include <nel/misc/displayer.h>
35 #include <nel/misc/vector.h>
36 #include <nel/misc/vectord.h>
37 #include <nel/misc/time_nl.h>
39 #include <nel/3d/u_camera.h>
40 #include <nel/3d/u_driver.h>
41 #include <nel/3d/u_text_context.h>
42 #include <nel/3d/u_instance.h>
43 #include <nel/3d/u_scene.h>
44 #include <nel/3d/u_material.h>
45 #include <nel/3d/u_landscape.h>
46 #include <nel/3d/u_skeleton.h>
48 #include <nel/3d/u_visual_collision_manager.h>
49 #include <nel/3d/u_visual_collision_entity.h>
51 #include <nel/pacs/u_move_container.h>
52 #include <nel/pacs/u_move_primitive.h>
53 #include <nel/pacs/u_global_retriever.h>
54 #include <nel/pacs/u_global_position.h>
56 #include "snowballs_client.h"
57 #include "entities.h"
58 #include "pacs.h"
59 #include "animation.h"
60 #include "camera.h"
61 #ifdef NL_OS_WINDOWS
62 #include "sound.h"
63 #endif
64 #include "mouse_listener.h"
65 #include "landscape.h"
68 // Namespaces
71 using namespace std;
72 using namespace NLMISC;
73 using namespace NL3D;
74 using namespace NLPACS;
76 namespace SBCLIENT {
79 // Variables
82 // A map of entities. All entities are later referred by their unique id
83 map<uint32, CEntity> Entities;
85 CEntity *Self = NULL;
87 // The size of the world, in meter
88 float WorldWidth = 20*160;
89 float WorldHeight = 6*160;
91 // Entity Id, only used offline
92 uint32 NextEID = 1000000;
94 // The speed settings
95 float PlayerSpeed = 10.0f; // 6.5 km/h
96 float SnowballSpeed = 15.0f; // 36 km/h
98 // these variables are set with the config file
100 // Setup for the name up the character
101 float EntityNameSize;
102 CRGBA EntityNameColor;
104 bool _TestCLS = false;
107 // Set the state of the entity (Appear, Normal, Disappear)
108 void CEntity::setState (TState state)
110 State = state;
111 StateStartTime = LocalTime;
115 // Get an map iterator on a entity, specified by its id
116 EIT findEntity (uint32 eid, bool needAssert)
118 EIT entity = Entities.find (eid);
119 if (entity == Entities.end () && needAssert)
121 nlerror ("Entity %u not found", eid);
123 return entity;
126 // -- -- things like Creature, Effect, Scenery seem more flexible than Self, Other, Snowball
127 // -- -- random keywords: entitybehavior (animations), entityinteraction (targetable, menu, )
128 // Creates an entity, given its id, its type (Self, Other, Snowball), its start and server positions.
129 void addEntity (uint32 eid, std::string name, CEntity::TType type, const CVector &startPosition, const CVector &serverPosition)
131 // nlinfo ("adding entity %u", eid);
133 // Check that the entity doesn't exist yet
134 EIT eit = findEntity (eid, false);
135 if (eit != Entities.end ())
137 nlerror ("Entity %d already exist", eid);
140 // Create a new entity
141 eit = (Entities.insert (make_pair (eid, CEntity()))).first;
142 CEntity &entity = (*eit).second;
144 // Check that in the case the entity newly created is a Self, there's not a Self yet.
145 if (type == CEntity::Self)
147 if (Self != NULL)
148 nlerror("Self entity already created");
150 Self = &entity;
153 // Set the entity up
154 entity.Id = eid;
155 entity.Type = type;
156 entity.Name = name;
157 entity.Position = startPosition;
158 entity.Angle = 0.0f;
159 entity.ServerPosition = serverPosition;
160 entity.VisualCollisionEntity = VisualCollisionManager->createEntity();
162 // setup the move primitive and the mesh instance depending on the type of entity
163 switch (type)
165 case CEntity::Self:
166 // create a move primitive associated to the entity
167 entity.MovePrimitive = MoveContainer->addCollisionablePrimitive(0, 1);
168 // it's a cylinder
169 entity.MovePrimitive->setPrimitiveType(UMovePrimitive::_2DOrientedCylinder);
170 // the entity should slide against obstacles
171 entity.MovePrimitive->setReactionType(UMovePrimitive::Slide);
172 // do not generate event if there is a collision
173 entity.MovePrimitive->setTriggerType(UMovePrimitive::NotATrigger);
174 // which entity should collide against me
175 entity.MovePrimitive->setCollisionMask(OtherCollisionBit+SnowballCollisionBit+StaticCollisionBit);
176 // the self collision bit
177 entity.MovePrimitive->setOcclusionMask(SelfCollisionBit);
178 // the self is an obstacle
179 entity.MovePrimitive->setObstacle(true);
180 // the size of the cylinder
181 entity.MovePrimitive->setRadius(1.0f);
182 entity.MovePrimitive->setHeight(1.8f);
183 // only use one world image, so use insert in world image 0
184 entity.MovePrimitive->insertInWorldImage(0);
185 // retrieve the start position of the entity
186 entity.MovePrimitive->setGlobalPosition(CVectorD(startPosition.x, startPosition.y, startPosition.z), 0);
188 // create instance of the mesh character
189 entity.Instance = Scene->createInstance ("gnu.shape");
190 entity.Skeleton = Scene->createSkeleton ("gnu.skel");
191 // use the instance on the skeleton
192 entity.Skeleton.bindSkin (entity.Instance);
194 // Allow the skeleton to cast shadows.
195 entity.Skeleton.enableCastShadowMap(true);
197 entity.Instance.hide ();
199 entity.Angle = MouseListener->getOrientation();
201 // setup final parameters
202 entity.Speed = PlayerSpeed;
203 entity.Particule = Scene->createInstance ("appear.ps");
204 entity.setState (CEntity::Appear);
205 playAnimation (entity, LogInAnim);
206 playAnimation (entity, IdleAnim);
208 break;
209 case CEntity::Other:
210 entity.MovePrimitive = MoveContainer->addCollisionablePrimitive(0, 1);
211 entity.MovePrimitive->setPrimitiveType(UMovePrimitive::_2DOrientedCylinder);
212 entity.MovePrimitive->setReactionType(UMovePrimitive::Slide);
213 entity.MovePrimitive->setTriggerType(UMovePrimitive::NotATrigger);
214 entity.MovePrimitive->setCollisionMask(OtherCollisionBit+SelfCollisionBit+SnowballCollisionBit);
215 entity.MovePrimitive->setOcclusionMask(OtherCollisionBit);
216 entity.MovePrimitive->setObstacle(true);
217 entity.MovePrimitive->setRadius(1.0f);
218 entity.MovePrimitive->setHeight(1.8f);
219 entity.MovePrimitive->insertInWorldImage(0);
220 entity.MovePrimitive->setGlobalPosition(CVectorD(startPosition.x, startPosition.y, startPosition.z), 0);
222 entity.Instance = Scene->createInstance ("gnu.shape");
223 entity.Skeleton = Scene->createSkeleton ("gnu.skel");
224 entity.Skeleton.bindSkin (entity.Instance);
225 entity.Instance.hide ();
227 entity.Speed = PlayerSpeed;
228 entity.Particule = Scene->createInstance ("appear.ps");
229 entity.setState (CEntity::Appear);
230 playAnimation (entity, LogInAnim);
231 playAnimation (entity, IdleAnim);
233 break;
234 case CEntity::Snowball:
235 entity.MovePrimitive = NULL;
237 // allows collision snapping to the ceiling
238 entity.VisualCollisionEntity->setCeilMode(true);
240 entity.Instance = Scene->createInstance ("snowball.shape");
241 entity.Skeleton = NULL;
242 entity.Speed = SnowballSpeed;
244 // -- -- riiiiight
245 //#ifdef NL_OS_WINDOWS
246 // playSound (entity, SoundId);
247 //#endif
248 entity.setState (CEntity::Normal);
249 break;
252 if (!entity.Skeleton.empty())
253 entity.Skeleton.setPos (startPosition);
255 entity.Instance.setPos (startPosition);
257 // todo sound
258 // if (entity.Source != NULL)
259 // entity.Source->setPosition (startPosition);
261 if (!entity.Particule.empty())
262 entity.Particule.setPos (startPosition);
266 // effectively remove the entity (don't play animation)
267 void deleteEntity (CEntity &entity)
269 if (!entity.Particule.empty())
271 Scene->deleteInstance (entity.Particule);
272 entity.Particule = NULL;
275 deleteAnimation (entity);
277 if (!entity.Skeleton.empty())
279 entity.Skeleton.detachSkeletonSon (entity.Instance);
280 Scene->deleteSkeleton (entity.Skeleton);
281 entity.Skeleton = NULL;
284 if (!entity.Instance.empty())
286 Scene->deleteInstance (entity.Instance);
287 entity.Instance = NULL;
290 if (entity.VisualCollisionEntity != NULL)
292 VisualCollisionManager->deleteEntity (entity.VisualCollisionEntity);
293 entity.VisualCollisionEntity = NULL;
296 if (entity.MovePrimitive != NULL)
298 MoveContainer->removePrimitive(entity.MovePrimitive);
299 entity.MovePrimitive = NULL;
302 //#ifdef NL_OS_WINDOWS
303 // deleteSound (entity);
304 //#endif
306 // nlinfo ("Remove the entity %u from the Entities list", entity.Id);
307 EIT eit = findEntity (entity.Id);
308 Entities.erase (eit);
312 // Remove an entity specified by its id
313 // The entity passes into the Disappear state
314 void removeEntity (uint32 eid)
316 // nlinfo ("removing entity %u", eid);
318 // look for the entity
319 EIT eit = findEntity (eid);
320 CEntity &entity = (*eit).second;
322 // if there is a particle system linked, delete it
323 if (!entity.Particule.empty())
325 Scene->deleteInstance (entity.Particule);
326 entity.Particule = NULL;
329 // if (entity.Type == CEntity::Other)
332 entity.Particule = Scene->createInstance("disappear.ps");
333 entity.Particule.setPos (entity.Position);
336 playAnimation (entity, LogOffAnim, true);
337 entity.setState (CEntity::Disappear);
340 void removeAllEntitiesExceptUs ()
342 EIT eit, nexteit;
344 // move entities
345 for (eit = Entities.begin (); eit != Entities.end (); )
347 nexteit = eit; nexteit++;
349 CEntity &entity = (*eit).second;
351 if (entity.Type != CEntity::Self)
353 // effectively remove the entity (don't play animation)
354 deleteEntity (entity);
357 eit = nexteit;
361 void deleteAllEntities()
363 EIT eit, nexteit;
364 for (eit = Entities.begin(); eit != Entities.end(); )
366 nexteit = eit; nexteit++;
367 CEntity &entity = (*eit).second;
368 deleteEntity (entity);
369 eit = nexteit;
371 Self = NULL;
378 // What to do when the entity appears
379 void stateAppear (CEntity &entity)
381 // after 1 second, show the instance
382 if (LocalTime > entity.StateStartTime + 1.0)
384 if (entity.Instance.getVisibility () != UTransform::Show)
385 entity.Instance.show ();
388 // after 5 seconds, delete the particle system (if any)
389 // and pass the entity into the Normal state
390 if (LocalTime > entity.StateStartTime + 3.0)
392 if (!entity.Particule.empty())
394 Scene->deleteInstance (entity.Particule);
395 entity.Particule = NULL;
398 entity.setState (CEntity::Normal);
401 if (entity.MovePrimitive != NULL)
402 entity.MovePrimitive->move(CVector(0,0,0), 0);
405 // What to do when the entity disappears
406 void stateDisappear (CEntity &entity)
408 // after 1 second, remove the mesh and all collision stuff
409 if (LocalTime > entity.StateStartTime + 1.0)
411 if (entity.Instance.getVisibility () != UTransform::Hide)
413 if (entity.Type == CEntity::Self)
415 if (Self == NULL)
416 nlerror("Self entity doesn't exist");
417 Self = NULL;
420 entity.Instance.hide ();
424 // after 5 seconds, remove the particle system and the entity entry
425 if (LocalTime > entity.StateStartTime + 3.0)
427 deleteEntity (entity);
429 else
431 if (entity.MovePrimitive != NULL)
432 entity.MovePrimitive->move(CVector(0,0,0), 0);
436 void stateNormal (CEntity &entity)
438 double dt = LocalTimeDelta;
439 CVector oldPos;
440 CVector newPos;
442 oldPos = entity.Position;
443 CVector pDelta = entity.Position - entity.ServerPosition;
444 CVector pDeltaOri = pDelta;
445 pDelta.z = 0.0f;
447 // -- -- simple random bots =) share with server
449 // find a new random server position
450 if (entity.Type == CEntity::Other && entity.AutoMove)
452 switch (entity.BotState)
454 case 0:
455 // choose something to do
456 if (frand(1.0f) > 0.5f)
457 entity.BotState = 5;
458 else
459 entity.BotState = 2;
460 break;
461 case 1:
462 // walk
463 if (pDelta.norm() < 0.1f || LocalTime - entity.BotStateStart > 3.000)
465 // reached the point
466 entity.BotState = 0;
468 else
470 // entity.IsWalking = true;
471 // entity.IsAiming = false;
473 break;
474 case 2:
475 // aim
476 entity.IsWalking = false;
477 entity.IsAiming = true;
478 entity.BotStateStart = LocalTime;
479 entity.BotState = 3;
480 break;
481 case 3:
482 // wait to shoot
483 entity.IsWalking = false;
484 entity.IsAiming = true;
485 if (LocalTime - entity.BotStateStart > 1.000)
487 entity.BotState = 4;
488 entity.BotStateStart = LocalTime;
489 CVector AimingPosition = entity.Position+CVector(0.0f, 0.0f, 2.0f);
490 CVector direction = CVector((float)(cos(entity.Angle)), (float)(sin(entity.Angle)), 0.3f).normed();
491 CVector AimedTarget = getTarget(AimingPosition,
492 direction,
493 100);
494 shotSnowball(NextEID++, entity.Id, AimingPosition, AimedTarget, SnowballSpeed, 3.0f);
496 break;
497 case 4:
498 // shoot
499 entity.IsWalking = false;
500 entity.IsAiming = false;
501 if (LocalTime - entity.BotStateStart > 1.000)
503 entity.BotState = 5;
504 entity.BotStateStart = LocalTime;
506 break;
507 case 5:
508 // choose a direction
509 float EntityMaxSpeed = 10.0f;
510 entity.AuxiliaryAngle += frand(1.5f)-0.75f;
511 entity.ServerPosition += CVector((float)cos(entity.AuxiliaryAngle),
512 (float)sin(entity.AuxiliaryAngle),
513 0.0f)*EntityMaxSpeed;
514 entity.BotState = 1;
515 entity.BotStateStart = LocalTime;
516 break;
521 if (entity.Type == CEntity::Snowball && LocalTime >= entity.Trajectory.getStopTime())
524 CVector tp(1140,-833,30);
525 nlinfo("dist=%f", (entity.Position-tp).norm());
526 if ((entity.Position-tp).norm()<30.0f)
528 static UInstance t = NULL;
529 if (t != NULL)
531 Scene->deleteInstance (t);
533 t = Scene->createInstance("pills.ps");
534 t->setScale (10,10,10);
535 CVector tp2 = tp;
536 tp2.z+=20;
537 t->setPos (tp2);
538 nlinfo("touche");
541 removeEntity(entity.Id);
546 // control the character animation
547 if (entity.Type != CEntity::Snowball)
549 if (entity.IsAiming && !entity.WasAiming)
551 // start aiming
552 playAnimation (entity, PrepareSnowBall, true);
553 playAnimation (entity, PrepareSnowBallCycle, false);
555 else if (entity.WasAiming && !entity.IsAiming)
557 /* // end aiming
558 playAnimation (entity, ThrowSnowball, true);
560 if (entity.IsWalking)
561 playAnimation (entity, WalkAnim);
562 else
563 playAnimation (entity, IdleAnim);
564 */ }
565 else if (entity.WasAiming && entity.IsAiming)
567 // currently aiming => do northing
569 else if (!entity.WasWalking && entity.IsWalking)
571 playAnimation (entity, PrepareWalkAnim, true);
572 playAnimation (entity, WalkAnim);
574 else if (entity.WasWalking && !entity.IsWalking)
576 playAnimation (entity, IdleAnim, true);
579 entity.WasAiming = entity.IsAiming;
580 entity.WasWalking = entity.IsWalking;
584 entity.ImmediateSpeed = CVector::Null;
586 if (entity.Type == CEntity::Self)
588 // get new position
589 newPos = MouseListener->getPosition();
590 // get new orientation
591 entity.Angle = MouseListener->getOrientation();
593 // Interpolate the character orientation towards the server angle
594 // for smoother movements
595 float sweepDistance = entity.AuxiliaryAngle-entity.InterpolatedAuxiliaryAngle;
596 if (sweepDistance > (float)Pi)
598 sweepDistance -= (float)Pi*2.0f;
599 entity.InterpolatedAuxiliaryAngle += (float)Pi*2.0f;
601 if (sweepDistance < -(float)Pi)
603 sweepDistance += (float)Pi*2.0f;
604 entity.InterpolatedAuxiliaryAngle -= (float)Pi*2.0f;
606 float sweepAngle = 4.0f*sweepDistance;
607 entity.InterpolatedAuxiliaryAngle += (float)(sweepAngle*dt);
608 if ((entity.AuxiliaryAngle-entity.InterpolatedAuxiliaryAngle)*sweepAngle <= 0.0)
609 entity.InterpolatedAuxiliaryAngle = entity.AuxiliaryAngle;
610 entity.Angle += entity.InterpolatedAuxiliaryAngle;
612 // tell the move container how much the entity should move
613 if (entity.IsWalking)
615 entity.ImmediateSpeed = (newPos-oldPos)/(float)dt;
616 if (_TestCLS) entity.MovePrimitive->setGlobalPosition(newPos, 0);
617 else entity.MovePrimitive->move(entity.ImmediateSpeed, 0);
620 else if (entity.Type == CEntity::Other)
622 // go to the server position with linear interpolation
623 // -- -- useful for speed limiting on frontend service
624 // -- -- random note: also, get rid of the position service,
625 // and move the snowball physics to a more useful service
627 // Interpolate orientation for smoother motions
628 // AuxiliaryAngle -> the server imposed angle
629 // InterpolatedAuxiliaryAngle -> the angle showed by the entity
630 float sweepDistance = entity.AuxiliaryAngle-entity.InterpolatedAuxiliaryAngle;
631 if (sweepDistance > (float)Pi)
633 sweepDistance -= (float)Pi*2.0f;
634 entity.InterpolatedAuxiliaryAngle += (float)Pi*2.0f;
636 if (sweepDistance < -(float)Pi)
638 sweepDistance += (float)Pi*2.0f;
639 entity.InterpolatedAuxiliaryAngle -= (float)Pi*2.0f;
641 float sweepAngle = 4.0f*sweepDistance;
642 entity.InterpolatedAuxiliaryAngle += (float)(sweepAngle*dt);
643 if ((entity.AuxiliaryAngle-entity.InterpolatedAuxiliaryAngle)*sweepAngle <= 0.0)
644 entity.InterpolatedAuxiliaryAngle = entity.AuxiliaryAngle;
646 entity.Angle = entity.InterpolatedAuxiliaryAngle;
648 // if (entity.IsWalking)
649 if (pDelta.norm() > 0.1f)
651 pDelta.normalize();
652 entity.ImmediateSpeed = pDelta*(-entity.Speed);
653 entity.MovePrimitive->move(entity.ImmediateSpeed, 0);
654 entity.IsWalking = true;
656 else
658 entity.IsWalking = false;
661 else if (entity.Type == CEntity::Snowball)
663 // go to the server position using trajectory interpolation
664 CVector newPos = entity.Trajectory.eval(LocalTime);
665 if (newPos != entity.Position)
667 entity.Position = entity.Trajectory.eval(LocalTime);
668 entity.Instance.show ();
671 else
673 // automatic speed
674 newPos = oldPos;
682 void updateEntities ()
684 // compute the delta t that has elapsed since the last update (in seconds)
685 double dt = LocalTimeDelta;
686 EIT eit, nexteit;
688 // move entities
689 for (eit = Entities.begin (); eit != Entities.end (); )
691 nexteit = eit; nexteit++;
693 CEntity &entity = (*eit).second;
695 switch (entity.State)
697 case CEntity::Appear:
698 stateAppear (entity);
699 break;
700 case CEntity::Normal:
701 stateNormal (entity);
702 break;
703 case CEntity::Disappear:
704 stateDisappear (entity);
705 break;
706 default:
707 nlstop;
708 break;
711 eit = nexteit;
714 // evaluate collisions
715 MoveContainer->evalCollision(dt, 0);
717 // snap entities to the ground
718 for (eit = Entities.begin (); eit != Entities.end (); eit++)
720 CEntity &entity = (*eit).second;
721 UGlobalPosition gPos;
723 if (entity.MovePrimitive != NULL)
725 // get the global position in pacs coordinates system
726 entity.MovePrimitive->getGlobalPosition(gPos, 0);
727 // convert it in a vector 3d
728 entity.Position = GlobalRetriever->getGlobalPosition(gPos);
729 // get the good z position
730 gPos.LocalPosition.Estimation.z = 0.0f;
731 entity.Position.z = GlobalRetriever->getMeanHeight(gPos);
733 // check position retrieving
735 UGlobalPosition gPosCheck;
736 gPosCheck = GlobalRetriever->retrievePosition(entity.Position);
737 if (gPos.InstanceId != gPosCheck.InstanceId ||
738 gPos.LocalPosition.Surface != gPosCheck.LocalPosition.Surface)
740 nlwarning("Checked UGlobalPosition differs from store");
741 // gPos.InstanceId = gPosCheck.InstanceId;
742 // gPos.LocalPosition.Surface = gPosCheck.LocalPosition.Surface;
745 // snap to the ground
746 if (!GlobalRetriever->isInterior(gPos))
747 entity.VisualCollisionEntity->snapToGround(entity.Position);
749 if (entity.Type == CEntity::Other &&
750 (entity.ServerPosition-entity.Position)*entity.ImmediateSpeed < 0.0f)
752 // nlinfo("detected over entity %d", entity.Id);
753 entity.ServerPosition.z = entity.Position.z;
754 entity.Position = entity.ServerPosition;
755 if (!GlobalRetriever->isInterior(gPos))
756 entity.VisualCollisionEntity->snapToGround(entity.Position);
757 entity.MovePrimitive->setGlobalPosition(CVectorD(entity.Position.x, entity.Position.y, entity.Position.z), 0);
762 if (!entity.Instance.empty())
764 CVector jdir;
765 switch (entity.Type)
767 case CEntity::Self:
768 jdir = CVector(-(float)cos(entity.Angle - (Pi * 0.5)), -(float)sin(entity.Angle - (Pi * 0.5)), 0.0f);
769 break;
770 case CEntity::Other:
771 jdir = CVector(-(float)cos(entity.Angle - (Pi * 0.5)), -(float)sin(entity.Angle - (Pi * 0.5)), 0.0f);
772 break;
773 case CEntity::Snowball:
774 jdir = entity.Trajectory.evalSpeed(LocalTime).normed();
775 break;
778 if (!entity.Skeleton.empty())
780 entity.Skeleton.setPos(entity.Position);
781 entity.Skeleton.setRotQuat(jdir);
784 entity.Instance.setPos(entity.Position);
785 entity.Instance.setRotQuat(jdir);
788 // todo sound
789 // if (entity.Source != NULL)
790 // entity.Source->setPosition (entity.Position);
792 if (!entity.Particule.empty())
794 entity.Particule.setPos(entity.Position);
797 if (entity.Type == CEntity::Self)
799 MouseListener->setPosition(entity.Position);
804 // Draw entities names up the characters
805 void renderEntitiesNames ()
807 // Setup the driver in matrix mode
808 Driver->setMatrixMode3D (Camera);
809 // Setup the drawing context
810 TextContext->setHotSpot (UTextContext::MiddleTop);
811 TextContext->setColor (EntityNameColor);
812 TextContext->setFontSize ((uint32)EntityNameSize);
814 for (EIT eit = Entities.begin (); eit != Entities.end (); eit++)
816 CEntity &entity = (*eit).second;
817 if (!entity.Instance.empty() && entity.Type == CEntity::Other)
819 CMatrix mat = Camera.getMatrix();
820 mat.setPos(entity.Position + CVector(0.0f, 0.0f, 4.0f));
821 mat.scale(10.0f);
822 TextContext->render3D(mat, entity.Name);
828 // The entities preferences callback
829 void cbUpdateEntities (CConfigFile::CVar &var)
831 if (var.Name == "EntityNameColor") EntityNameColor.set (var.asInt(0), var.asInt(1), var.asInt(2), var.asInt(3));
832 else if (var.Name == "EntityNameSize") EntityNameSize = var.asFloat ();
833 else nlwarning ("Unknown variable update %s", var.Name.c_str());
836 void initEntities()
838 ConfigFile->setCallback ("EntityNameColor", cbUpdateEntities);
839 ConfigFile->setCallback ("EntityNameSize", cbUpdateEntities);
841 cbUpdateEntities (ConfigFile->getVar ("EntityNameColor"));
842 cbUpdateEntities (ConfigFile->getVar ("EntityNameSize"));
845 void releaseEntities()
847 // Remove config file callbacks
848 ConfigFile->setCallback("EntityNameColor", NULL);
849 ConfigFile->setCallback("EntityNameSize", NULL);
851 // Delete all entities (should already have been called normally)
852 deleteAllEntities();
856 // Reset the pacs position of an entity, in case pacs went wrong
857 void resetEntityPosition(uint32 eid)
859 uint32 sbid = NextEID++;
860 EIT eit = findEntity (eid);
862 CEntity &entity = (*eit).second;
864 UGlobalPosition gPos;
865 // get the global position
866 gPos = GlobalRetriever->retrievePosition(entity.Position);
867 // convert it in a vector 3d
868 entity.Position = GlobalRetriever->getGlobalPosition(gPos);
869 // get the good z position
870 gPos.LocalPosition.Estimation.z = 0.0f;
871 entity.Position.z = GlobalRetriever->getMeanHeight(gPos);
873 // snap to the ground
874 if (entity.VisualCollisionEntity != NULL && !GlobalRetriever->isInterior(gPos))
875 entity.VisualCollisionEntity->snapToGround(entity.Position);
877 if (entity.MovePrimitive != NULL)
878 entity.MovePrimitive->setGlobalPosition(CVector(entity.Position.x, entity.Position.y, entity.Position.z), 0);
882 void shotSnowball(uint32 sid, uint32 eid, const CVector &start, const CVector &target, float speed, float deflagRadius)
884 // get direction
885 CVector direction = (target-start).normed();
887 // create a new snowball entity
888 addEntity(sid, "", CEntity::Snowball, start, target);
889 EIT sit = findEntity (sid);
890 CEntity &snowball = (*sit).second;
892 snowball.AutoMove = 1;
893 snowball.Trajectory.init(start, target, speed, LocalTime + 1.000);
894 snowball.Instance.hide();
896 EIT eit = findEntity (eid);
897 CEntity &entity = (*eit).second;
899 // end aiming
900 playAnimation (entity, ThrowSnowball, true);
902 if (entity.IsWalking)
904 playAnimation (entity, PrepareWalkAnim, true);
905 playAnimation (entity, WalkAnim);
907 else
908 playAnimation (entity, IdleAnim);
914 // Commands
917 NLMISC_COMMAND(remove_entity,"remove a local entity","<eid>")
919 // check args, if there s not the right number of parameter, return bad
920 if(args.size() != 1) return false;
922 uint32 eid = (uint32)atoi(args[0].c_str());
923 removeEntity (eid);
925 return true;
929 NLMISC_COMMAND(add_entity,"add a local entity","<nb_entities> <auto_update>")
931 // check args, if there s not the right number of parameter, return bad
932 if(args.size() != 2) return false;
934 uint nb = (uint)atoi(args[0].c_str());
936 for (uint i = 0; i < nb ; i++)
938 uint32 eid = NextEID++;
939 CVector start(ConfigFile->getVar("StartPoint").asFloat(0), ConfigFile->getVar("StartPoint").asFloat(1), ConfigFile->getVar("StartPoint").asFloat(2));
940 addEntity (eid, "Entity"+toString(eid), CEntity::Other, start, start);
941 EIT eit = findEntity (eid);
942 (*eit).second.AutoMove = atoi(args[1].c_str()) == 1;
945 return true;
948 NLMISC_COMMAND(speed,"set the player speed","[<entity_id>] <speed in km/h>")
950 // check args, if there s not the right number of parameter, return bad
951 if(args.size() == 1)
953 float speed = min( max( (float)atof(args[0].c_str()), 0.1f ), 200.0f ); // speed range in km/h
954 if (Self != NULL)
956 MouseListener->setSpeed( speed / 3.6f );
957 Self->Speed = speed / 3.6f;
960 else if(args.size() == 2)
962 float speed = min( max( (float)atof(args[1].c_str()), 0.1f ), 200.0f ); // speed range in km/h
964 uint eid = (uint)atoi(args[0].c_str());
965 EIT eit = findEntity (eid);
966 CEntity &entity = (*eit).second;
968 entity.Speed = speed / 3.6f;
969 if (entity.Type == CEntity::Self)
971 MouseListener->setSpeed(entity.Speed);
974 return true;
977 NLMISC_COMMAND(goto, "go to a given position", "<x> <y>")
979 // check args, if there s not the right number of parameter, return bad
980 if(args.size() != 2) return false;
982 if (Self == NULL) return false;
984 CEntity &entity = *Self;
986 float x, y;
988 x = (float)atof(args[0].c_str());
989 y = (float)atof(args[1].c_str());
992 if (entity.MovePrimitive != NULL && entity.VisualCollisionEntity != NULL)
994 UGlobalPosition gPos;
995 entity.MovePrimitive->setGlobalPosition(CVectorD(x, y, 0.0f), 0);
996 // get the global position in pacs coordinates system
997 entity.MovePrimitive->getGlobalPosition(gPos, 0);
998 // convert it in a vector 3d
999 entity.Position = GlobalRetriever->getGlobalPosition(gPos);
1000 // get the good z position
1001 gPos.LocalPosition.Estimation.z = 0.0f;
1002 entity.Position.z = GlobalRetriever->getMeanHeight(gPos);
1003 // snap to the ground
1004 if (!GlobalRetriever->isInterior(gPos))
1005 entity.VisualCollisionEntity->snapToGround( entity.Position );
1007 if (entity.Type == CEntity::Self)
1009 MouseListener->setPosition(entity.Position);
1013 return true;
1016 NLMISC_COMMAND(entities, "display all entities info", "")
1018 // check args, if there s not the right number of parameter, return bad
1019 if(args.size() != 0) return false;
1021 for (EIT eit = Entities.begin (); eit != Entities.end (); eit++)
1023 CEntity &e = (*eit).second;
1024 log.displayNL("%s %u (k%u) %s %d", (Self==&e)?"*":" ", e.Id, (*eit).first, e.Name.c_str(), e.Type);
1026 return true;
1029 NLMISC_COMMAND(test_cls, "test the collision service, disables collision test on self", "")
1031 _TestCLS = !_TestCLS;
1032 return true;
1035 } /* namespace SBCLIENT */
1037 /* end of file */