1 /* 2 * Copyright (C) 2002-2020 by the Widelands Development Team 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 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 General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 * 18 */ 19 20 #ifndef WL_LOGIC_MAP_OBJECTS_BOB_H 21 #define WL_LOGIC_MAP_OBJECTS_BOB_H 22 23 #include "base/macros.h" 24 #include "base/vector.h" 25 #include "economy/route.h" 26 #include "graphic/animation/diranimations.h" 27 #include "logic/map_objects/info_to_draw.h" 28 #include "logic/map_objects/map_object.h" 29 #include "logic/map_objects/map_object_program.h" 30 #include "logic/map_objects/walkingdir.h" 31 #include "logic/path.h" 32 #include "logic/widelands_geometry.h" 33 34 namespace Widelands { 35 36 class Bob; 37 38 /** 39 * Implement MapObjectDescr for the following \ref Bob class. 40 */ 41 class BobDescr : public MapObjectDescr { 42 public: 43 friend struct MapBobdataPacket; 44 45 BobDescr(const std::string& init_descname, 46 const MapObjectType type, 47 MapObjectDescr::OwnerType owner_type, 48 const LuaTable& table); 49 ~BobDescr()50 ~BobDescr() override { 51 } 52 53 Bob& create(EditorGameBase&, Player* owner, const Coords&) const; 54 get_owner_type()55 MapObjectDescr::OwnerType get_owner_type() const { 56 return owner_type_; 57 } 58 movecaps()59 virtual uint32_t movecaps() const { 60 return 0; 61 } 62 uint32_t vision_range() const; 63 64 protected: 65 virtual Bob& create_object() const = 0; 66 67 private: 68 const MapObjectDescr::OwnerType owner_type_; 69 const uint32_t vision_range_; 70 DISALLOW_COPY_AND_ASSIGN(BobDescr); 71 }; 72 73 /** 74 * Bobs are moving map objects: Animals, humans, ships... 75 * 76 * The name comes from original Settlers2 terminology. 77 * 78 * \par Bobs, Tasks and their signalling 79 * 80 * Bobs have a call-stack of "tasks". The top-most \ref Task is the one that is 81 * currently being executed. 82 * 83 * Upon initialization, an object has no Task at all. A CMD_ACT will be 84 * scheduled automatically. When it is executed, \ref init_auto_task() is 85 * called to automatically select a fallback Task. 86 * 87 * However, the creator of the Bob can choose to push a specific Task 88 * immediately after creating the Bob. This will override the fallback 89 * behaviour. init_auto_task() is also called when the final task is popped 90 * from the stack. 91 * 92 * All state information that a Task uses must be stored in the State structure 93 * returned by get_state(). Every Task on the Task stack has its own 94 * State structure, i.e. push_task() does not destroy the current Task's State. 95 * 96 * In order to start a new sub-task, you have to call \ref push_task(), and then 97 * fill the State structure returned by get_state() with any parameters that the 98 * Task may need. 99 * 100 * A Task is ended by \ref pop_task(). Note, however, that pop_task() can only 101 * be called from a Task's update() function. If you want to interrupt the 102 * current \ref Task for some reason, you should call \ref send_signal(). 103 * The signal semantics are explained below in more detail. 104 * 105 * To implement a new Task, you need to create a new Task object with an 106 * update() function. This update() function is called in one of the following 107 * situations: 108 * \li a timeout set by \ref schedule_act() has occurred 109 * \li the task has just been started via \ref push_task() 110 * \li the child task has ended via \ref pop_task() 111 * \li a signal has been sent via \ref send_signal() 112 * It is the responsibility of the update() function to distinguish between 113 * these situations as appropriate. 114 * 115 * One of the following things must happen during update(): 116 * \li Call schedule_act() to schedule the next call to update() 117 * \li Call skip_act() if you really don't want to act until a signal occurs. 118 * \li Call pop_task() to end the current task 119 * \li Send a new signal via \ref send_signal(). Note that in this case, 120 * the update() function will be called again after some delay, and it 121 * remains the responsibility of the update() function to deal with the 122 * signal. 123 * The last case is mostly useful when signals are sent from functions that 124 * can be called at any time, such as \ref set_location(). 125 * 126 * Whenever \ref send_signal() is called, any current signal is overwritten 127 * by the new signal and the signal_immediate() functions of all Tasks on the 128 * stack are called if available. Note that these functions are not supposed 129 * to perform any actions besides bookkeeping actions that must be performed 130 * in all situations (for example, one might zero some pointer in 131 * signal_immediate() to avoid dangling pointers). 132 * 133 * Then, \ref send_signal() schedules a future call to the top-most task's 134 * update() function. Often, update() functions will just call \ref pop_task() 135 * and leave the signal handling to their parent tasks. To ultimately handle 136 * a signal, the update() function must call \ref signal_handled(). 137 * 138 * If a task maintains state outside of its \ref State structure, it may have 139 * to do certain bookkeeping tasks whenever the task is popped from the stack. 140 * To this end, a task may have a \ref Task::pop method. If this method 141 * exists, it is always called just before the task is popped from the stack. 142 */ 143 class Bob : public MapObject { 144 public: 145 friend class Map; 146 friend struct MapBobdataPacket; 147 friend struct MapBobPacket; 148 149 struct State; 150 using Ptr = void (Bob::*)(Game&, State&); 151 using PtrSignal = void (Bob::*)(Game&, State&, const std::string&); 152 153 /// \see struct Bob for in-depth explanation 154 struct Task { 155 char const* name; 156 157 /** 158 * Called to update the current task and schedule the next 159 * actions etc. 160 * 161 * \see Bob for in-depth explanation 162 */ 163 Ptr update; 164 165 /** 166 * Called by \ref send_signal() to perform bookkeeping tasks that 167 * must be performed immediately. May be zero. 168 */ 169 PtrSignal signal_immediate; 170 171 /** 172 * Called by \ref pop_task() just before the task is popped from 173 * the task. Must only perform bookkeeping tasks. May be zero. 174 */ 175 Ptr pop; 176 177 bool unique; /// At most 1 of this task type can be on the stack. 178 }; 179 180 /** 181 * The current state of a task on the stack. 182 * 183 * If you think in terms of functions, \ref Task represents the code 184 * of a function, while \ref State represents the stackframe of an 185 * actual execution of the function. 186 * 187 * \see class Bob for in-depth explanation 188 */ 189 struct State { 190 explicit State(const Task* const the_task = nullptr) taskState191 : task(the_task), 192 ivar1(0), 193 ivar2(0), 194 ivar3(0), 195 coords(Coords::null()), 196 path(nullptr), 197 route(nullptr), 198 program(nullptr) { 199 } 200 201 const Task* task; 202 int32_t ivar1; 203 int32_t ivar2; 204 int32_t ivar3; 205 ObjectPointer objvar1; 206 std::string svar1; 207 208 Coords coords; 209 DirAnimations diranims; 210 Path* path; 211 Route* route; 212 const MapObjectProgram* program; ///< pointer to current program 213 }; 214 MO_DESCR(BobDescr)215 MO_DESCR(BobDescr) 216 217 uint32_t get_current_anim() const { 218 return anim_; 219 } get_animstart()220 int32_t get_animstart() const { 221 return animstart_; 222 } 223 224 bool init(EditorGameBase&) override; 225 void cleanup(EditorGameBase&) override; 226 void act(Game&, uint32_t data) override; 227 void schedule_destroy(Game&); 228 void schedule_act(Game&, uint32_t tdelta); 229 void skip_act(); 230 Vector2f calc_drawpos(const EditorGameBase&, const Vector2f& field_on_dst, float scale) const; 231 void set_owner(Player*); 232 233 void set_position(EditorGameBase&, const Coords&); get_position()234 const FCoords& get_position() const { 235 return position_; 236 } get_next_bob()237 Bob* get_next_bob() const { 238 return linknext_; 239 } 240 241 /// Check whether this bob should be able to move onto the given node. 242 /// 243 /// \param commit indicates whether this function is called from the 244 /// \ref start_walk function, i.e. whether the bob will actually move 245 /// onto the \p to node if this function allows it to. 246 virtual bool check_node_blocked(Game&, const FCoords&, bool commit); 247 248 // Draws the bob onto the screen with 'field_on_dst' being the position of 249 // the field associated with this bob (if it is walking, that is its 250 // starting field) in pixel space of 'dst' (including scale). The 'scale' is 251 // required to draw the bob in the right size. 252 virtual void draw(const EditorGameBase&, 253 const InfoToDraw& info_to_draw, 254 const Vector2f& field_on_dst, 255 const Coords& coords, 256 float scale, 257 RenderTarget* dst) const; 258 259 // For debug 260 void log_general_info(const EditorGameBase&) const override; 261 262 // default tasks 263 void reset_tasks(Game&); 264 265 // TODO(feature-Hasi50): correct (?) Send a signal that may switch to some other \ref Task 266 void send_signal(Game&, char const*); 267 void start_task_idle(Game&, uint32_t anim, int32_t timeout); 268 bool is_idle(); 269 270 /// This can fail (and return false). Therefore the caller must check the 271 /// result and find something else for the bob to do. Otherwise there will 272 /// be a "failed to act" error. 273 bool start_task_movepath(Game&, 274 const Coords& dest, 275 const int32_t persist, 276 const DirAnimations&, 277 const bool forceonlast = false, 278 const int32_t only_step = -1, 279 const bool forceall = false) __attribute__((warn_unused_result)); 280 281 /// This can fail (and return false). Therefore the caller must check the 282 /// result and find something else for the bob to do. Otherwise there will 283 /// be a "failed to act" error. 284 void start_task_movepath(Game&, 285 const Path&, 286 const DirAnimations&, 287 const bool forceonlast = false, 288 const int32_t only_step = -1); 289 290 bool start_task_movepath(Game&, 291 const Path&, 292 const int32_t index, 293 const DirAnimations&, 294 const bool forceonlast = false, 295 const int32_t only_step = -1) __attribute__((warn_unused_result)); 296 297 void start_task_move(Game& game, int32_t dir, const DirAnimations&, bool); 298 299 // higher level handling (task-based) top_state()300 State& top_state() { 301 assert(stack_.size()); 302 return *stack_.rbegin(); 303 } get_state()304 State* get_state() { 305 return stack_.size() ? &*stack_.rbegin() : nullptr; 306 } 307 get_signal()308 std::string get_signal() { 309 return signal_; 310 } 311 State* get_state(const Task&); 312 State const* get_state(const Task&) const; 313 void push_task(Game& game, const Task& task, uint32_t tdelta = 10); 314 void pop_task(Game&); 315 316 void signal_handled(); 317 318 /// Automatically select a task. init_auto_task(Game &)319 virtual void init_auto_task(Game&) { 320 } 321 322 // low level animation and walking handling 323 void set_animation(EditorGameBase&, uint32_t anim); 324 325 /// \return true if we're currently walking is_walking()326 bool is_walking() { 327 return walking_ != IDLE; 328 } 329 330 /** 331 * This is a hack that should not be used, if possible. 332 * It is only introduced here because profiling showed 333 * that soldiers spend a lot of time in the node blocked check. 334 */ get_next_on_field()335 Bob* get_next_on_field() const { 336 return linknext_; 337 } 338 339 protected: 340 explicit Bob(const BobDescr& descr); 341 ~Bob() override; 342 343 private: 344 void do_act(Game&); 345 void do_pop_task(Game&); 346 void idle_update(Game&, State&); 347 void movepath_update(Game&, State&); 348 void move_update(Game&, State&); 349 350 int32_t start_walk(Game& game, WalkingDir, uint32_t anim, bool force = false); 351 352 /** 353 * Call this from your task_act() function that was scheduled after 354 * start_walk(). 355 */ end_walk()356 void end_walk() { 357 walking_ = IDLE; 358 } 359 360 static Task const taskIdle; 361 static Task const taskMovepath; 362 static Task const taskMove; 363 364 FCoords position_; ///< where are we right now? 365 Bob* linknext_; ///< next object on this node 366 Bob** linkpprev_; 367 uint32_t anim_; 368 int32_t animstart_; ///< gametime when the animation was started 369 WalkingDir walking_; 370 int32_t walkstart_; ///< start time (used for interpolation) 371 int32_t walkend_; ///< end time (used for interpolation) 372 373 // Task framework variables 374 std::vector<State> stack_; 375 376 /** 377 * Every time a Bob acts, this counter is incremented. 378 * 379 * All scheduled \ref Cmd_Act are given this ID as data, so that 380 * only the earliest \ref Cmd_Act issued during one act phase is actually 381 * executed. Subsequent \ref Cmd_Act could interfere and are eliminated. 382 */ 383 uint32_t actid_; 384 385 /** 386 * Whether something was scheduled during this act phase. 387 * 388 * The only purpose of this variable is to act as an integrity check to avoid 389 * Bobs that hang themselves up. So e.g. \ref skip_act() also sets this 390 * to \c true, even though it technically doesn't schedule anything. 391 */ 392 bool actscheduled_; 393 bool in_act_; ///< if do_act is currently running 394 std::string signal_; 395 396 // saving and loading 397 protected: 398 struct Loader : public MapObject::Loader { 399 public: 400 Loader(); 401 402 void load(FileRead&); 403 void load_pointers() override; 404 void load_finish() override; 405 406 protected: 407 virtual const Task* get_task(const std::string& name); 408 virtual const MapObjectProgram* get_program(const std::string& name); 409 410 private: 411 struct LoadState { 412 uint32_t objvar1; 413 Route::LoadData route; 414 }; 415 416 std::vector<LoadState> states; 417 }; 418 419 public: has_new_save_support()420 bool has_new_save_support() override { 421 return true; 422 } 423 424 void save(EditorGameBase&, MapObjectSaver&, FileWrite&) override; 425 // Pure Bobs cannot be loaded 426 }; 427 } // namespace Widelands 428 429 #endif // end of include guard: WL_LOGIC_MAP_OBJECTS_BOB_H 430