1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "event_reaction_container.h"
23 #include "state_profil.h"
24 #include "world_container.h"
26 #include "ai_instance.h"
27 #include "state_instance.h"
29 extern NLMISC::CVariable
<bool> LogAcceptablePos
;
31 using namespace AITYPES
;
33 std::string
CAIState::getIndexString () const
35 return getOwner()->getIndexString()+NLMISC::toString(":%u", getChildIndex());
38 void CAIState::updateDependencies (const CAIAliasDescriptionNode
&aliasTree
, CAliasTreeOwner
*aliasTreeOwner
)
40 switch(aliasTree
.getType())
44 CGroup
*const group
=NLMISC::safe_cast
<CGroup
*>(aliasTreeOwner
);
46 group
->getPersistentStateInstance()->setStartState(getOwner()->states().getChildByAlias(getAlias()));
52 CAIEventReaction
*const eventPtr
=NLMISC::safe_cast
<CAIEventReaction
*>(getOwner()->eventReactions().getAliasChildByAlias(aliasTree
.getAlias()));
56 eventPtr
->setState (getAlias());
57 eventPtr
->setType (CAIEventReaction::FixedState
);
64 IAliasCont
* CAIState::getAliasCont(TAIType type
)
68 case AITypeNpcStateProfile
:
70 case AITypeNpcStateChat
:
78 CAliasTreeOwner
* CAIState::createChild(IAliasCont
*cont
, CAIAliasDescriptionNode
*aliasTree
)
80 CAliasTreeOwner
* child
= NULL
;
82 switch(aliasTree
->getType())
84 case AITypeNpcStateProfile
:
85 child
= new CAIStateProfile(this, aliasTree
);
87 case AITypeNpcStateChat
:
88 child
= new CAIStateChat(this, aliasTree
);
93 cont
->addAliasChild(child
);
98 CAIState
*CStateInstance::getCAIState ()
103 bool CShape::setPath(TVerticalPos verticalPos
, const std::vector
<CAIVector
> &points
)
107 _VerticalPos
= verticalPos
;
110 _Geometry
.reserve(points
.size());
112 for (uint32 ind
=0;ind
<points
.size();ind
++)
114 RYAI_MAP_CRUNCH::CWorldPosition newpos
;
115 CWorldContainer::calcNearestWPosFromPosAnRadius(_VerticalPos
, newpos
, points
[ind
], 0, 1, CWorldContainer::CPosValidatorDefault());
117 if ( !newpos
.isValid()
118 && !_AcceptInvalidPos
)
120 CWorldContainer::calcNearestWPosFromPosAnRadius(_VerticalPos
, newpos
, points
[ind
], 6, 100, CWorldContainer::CPosValidatorDefault());
122 if (newpos
.isValid())
124 if (LogAcceptablePos
)
125 nlinfo("StatePositionnal 'ss'(uu): Path pos Error at position %s, an acceptable position could be %s (in 'ss')",
126 /*getAliasFullName().c_str(), getAlias(),*/
127 points
[ind
].toString().c_str(), newpos
.toString().c_str()/*, getAliasFullName().c_str()*/);
131 nlwarning("StatePositionel 'ss'(uu): Path pos Error at position %s, no acceptable position found around (in 'ss')",
132 /*getAliasFullName().c_str(), getAlias(),*/
133 points
[ind
].toString().c_str()/*, getAliasFullName().c_str()*/);
138 _Geometry
.push_back(newpos
);
145 bool CShape::contains (const CAIVector
&pos
) const
147 // Point or line can't contains !
148 if (_Geometry
.size() < 3)
151 // Check with the bounding rectangle of the zone
152 if ( (pos
.x() < _VMin
.x())
153 || (pos
.y() < _VMin
.y())
154 || (pos
.x() > _VMax
.x())
155 || (pos
.y() > _VMax
.y()) )
158 uint32 nNbIntersection
= 0;
159 for (uint32 i
= 0; i
<_Geometry
.size(); ++i
)
161 const CAIVector p1
= _Geometry
[i
];
162 const CAIVector p2
= _Geometry
[(i
+1)%_Geometry
.size()];
164 if ( (p1
.y() <= pos
.y())
165 && (p2
.y() <= pos
.y()) )
167 if ( (p1
.y() > pos
.y())
168 && (p2
.y() > pos
.y()) )
171 const double deltaX
=p2
.x()-p1
.x();
172 const double deltaY
=p2
.y()-p1
.y();
173 const double deltaYPos
=pos
.y()-p1
.y();
175 const double xinter
= (double)p1
.x() + deltaX
*(deltaYPos
/deltaY
);
176 if (xinter
> pos
.x())
179 return ((nNbIntersection
&1)==1); // odd intersections so the vertex is inside
182 bool CShape::setPatat(TVerticalPos verticalPos
, const std::vector
<CAIVector
> &points
)
185 _VerticalPos
= verticalPos
;
189 _Geometry
.reserve(points
.size());
191 // create a list of valid position inside the patat
193 CAIVector vMin
, vMax
;
195 // Point or line can't contains !
196 if (points
.size() < 3)
199 // Get the bounding rectangle of the zone
200 vMax
= vMin
= points
[0];
201 for (uint i
= 0; i
< points
.size(); ++i
)
203 if (vMin
.x() > points
[i
].x())
204 vMin
.setX(points
[i
].x());
205 if (vMin
.y() > points
[i
].y())
206 vMin
.setY(points
[i
].y());
208 if (vMax
.x() < points
[i
].x())
209 vMax
.setX(points
[i
].x());
210 if (vMax
.y() < points
[i
].y())
211 vMax
.setY(points
[i
].y());
217 // fill the geometry vector with invalid word pos
218 for (uint i
=0; i
<points
.size(); ++i
)
220 _Geometry
.push_back(TPosition(sint(points
[i
].x().asDouble()), sint(points
[i
].y().asDouble())));
222 // find a valid position for every geometric
224 RYAI_MAP_CRUNCH::CWorldPosition worldPos
;
225 if (!CWorldContainer::calcNearestWPosFromPosAnRadius (_VerticalPos
, worldPos
, points
[0], float((vMax
-vMin
).quickNorm()), 1000, CWorldContainer::CPosValidatorDefault()))
227 // nlwarning("Can't find valid pos for state position '%s'(%u)", getAliasFullName().c_str(), getAlias());
228 if (!_AcceptInvalidPos
)
230 nlwarning("Can't find valid pos for state at position %s", points
[0].toString().c_str());
236 buildRandomPos(worldPos
, float((vMax
-vMin
).quickNorm()));
239 // build the valid pos for each patat point
241 _Geometry
.reserve(points
.size());
242 for (uint32 ind
=0;ind
<points
.size();ind
++)
244 RYAI_MAP_CRUNCH::CWorldPosition newpos
;
245 CWorldContainer::calcNearestWPosFromPosAnRadius(_VerticalPos
, newpos
, points
[ind
], 0, 1, CWorldContainer::CPosValidatorDefault());
246 if ( !newpos
.isValid()
247 && !_AcceptInvalidPos
)
250 CWorldContainer::calcNearestWPosFromPosAnRadius(_VerticalPos
, newpos
, points
[ind
], 6, 100, CWorldContainer::CPosValidatorDefault());
252 if (newpos
.isValid())
254 if (LogAcceptablePos
)
255 nlinfo("Path pos Error at position %s, an acceptable position could be %s",
256 points
[ind
].toString().c_str(),
257 newpos
.toString().c_str());
259 // nlinfo("StatePrositionnal '%s'(%u): Path pos Error at position %s, an acceptable position could be %s (in '%s')",
260 // getAliasFullName().c_str(),
262 // points[ind].toString().c_str(),
263 // newpos.toString().c_str(),
264 // getAliasFullName().c_str());
268 nlwarning("Path pos Error at position %s, no acceptable position found around",
269 points
[ind
].toString().c_str());
274 _Geometry
.push_back(newpos
);
280 bool CShape::calcRandomPos(CAIPos
&pos
) const
283 (double(_VMin
.x()) + CAIS::rand32(_VMax
.x() - _VMin
.x()))/CAICoord::UNITS_PER_METER
,
284 (double(_VMin
.y()) + CAIS::rand32(_VMax
.y() - _VMin
.y()))/CAICoord::UNITS_PER_METER
);
285 if ((v
.x() < _VMin
.x()) || (v
.y() < _VMin
.y()) || (v
.x() > _VMax
.x()) || (v
.y() > _VMax
.y()))
288 uint32 nNbIntersection
= 0;
289 for (uint k
= 0; k
< _Geometry
.size(); ++k
)
291 const CAIVector
&p1
= _Geometry
[k
];
292 const CAIVector
&p2
= _Geometry
[(k
+1)%_Geometry
.size()];
294 if (((p1
.y()-v
.y()) < 0.0)&&((p2
.y()-v
.y()) < 0.0))
296 if (((p1
.y()-v
.y()) > 0.0)&&((p2
.y()-v
.y()) > 0.0))
298 if ((p2
.y()-p1
.y()) == 0)
301 const float delta
= (v
.y()-p1
.y()).asInt()/float(p2
.y()-p1
.y());
302 const float xinter
= (float)(p1
.x().asInt() + (p2
.x()-p1
.x()).asInt() * delta
);
306 if ((nNbIntersection
&1) == 1) // odd intersections so the vertex is inside
308 pos
= CAIPos(v
, 0, 0);