1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
|
/**
* @file
* @brief Functions for handling multi-turn actions.
**/
#pragma once
#include <vector>
#include "activity-interrupt-type.h"
#include "command-type.h"
#include "enum.h"
#include "equipment-slot.h"
#include "item-prop-enum.h"
#include "mpr.h"
#include "operation-types.h"
#include "seen-context-type.h"
#include "transformation.h"
using std::vector;
class interrupt_block
{
public:
interrupt_block(bool block = true) {
m_block = block;
if (block)
++interrupts_blocked;
}
~interrupt_block() {
if (m_block)
--interrupts_blocked;
}
static bool blocked() { return interrupts_blocked > 0; }
private:
bool m_block;
static int interrupts_blocked;
};
class monster;
struct ait_hp_loss;
enum class ai_payload // activity interrupt payloads
{
none,
int_payload,
string_payload,
monster,
hp_loss,
};
struct activity_interrupt_data
{
ai_payload apt;
union
{
const char* string_data;
const int* int_data;
const ait_hp_loss* ait_hp_loss_data;
monster* mons_data;
nullptr_t no_data;
};
seen_context_type context;
activity_interrupt_data()
: apt(ai_payload::none), no_data(nullptr), context(SC_NONE)
{
}
activity_interrupt_data(const int *i)
: apt(ai_payload::int_payload), int_data(i), context(SC_NONE)
{
}
activity_interrupt_data(const char *s)
: apt(ai_payload::string_payload), string_data(s), context(SC_NONE)
{
}
activity_interrupt_data(const string &s)
: apt(ai_payload::string_payload), string_data(s.c_str()),
context(SC_NONE)
{
}
activity_interrupt_data(monster* m, seen_context_type ctx = SC_NONE)
: apt(ai_payload::monster), mons_data(m), context(ctx)
{
}
activity_interrupt_data(const ait_hp_loss *ahl)
: apt(ai_payload::hp_loss), ait_hp_loss_data(ahl), context(SC_NONE)
{
}
};
struct ait_hp_loss
{
int hp;
int hurt_type; // KILLED_BY_POISON, etc.
ait_hp_loss(int _hp, int _ht) : hp(_hp), hurt_type(_ht) { }
};
class Delay
{
/**
* This is run if `started` is not yet true.
*/
virtual void start()
{ }
/**
* This is run before tick(); if it returns true, the delay is popped off
* the queue and handle() returns early.
*/
virtual bool invalidated()
{
return false;
}
/**
* This is run once each turn of the delay, including the first, but not if
* it has finished.
*/
virtual void tick()
{ }
/**
* If the delay has finished, this is run instead. It should contain the payload of
* the delay.
*/
virtual void finish()
{
mpr("You finish doing something buggy.");
}
protected:
bool started = false;
public:
int duration;
Delay(int dur) : duration{dur}
{ }
virtual ~Delay() = default;
/**
* @return whether this is a running delay (run, rest, travel), which
* involves moving/resting each turn until completed, rather than depending
* on `duration` itself.
*/
virtual bool is_run() const
{
return false;
}
/**
* @return whether this is a delay which relocates the player,
* which are generally uninterruptible but are interrupted by teleport.
* Note that no stairs are necessarily involved.
*/
virtual bool is_relocation() const
{
return is_stairs();
}
/**
* @return whether this involves going up or down stairs.
*/
virtual bool is_stairs() const
{
return false;
}
virtual bool is_resting() const
{
return false;
}
/**
* @return whether it's OK to start eating during this delay if hungry.
*/
virtual bool want_autoeat() const
{
return false;
}
virtual bool is_macro() const
{
return false;
}
/**
* @return true if this delay can act as a parent to other delays, i.e. if
* other delays can be spawned while this delay is running. If is_parent
* returns true, new delays will be pushed immediately to the front of the
* delay in question, rather than at the end of the queue.
*/
virtual bool is_parent() const
{
return false;
}
/**
* This is called exactly each turn that the delay is active.
*/
virtual void handle();
/**
* This is called on the front of the delay queue when stop_delay is called.
* If the player needs to be notified, it should also print a message.
* @return whether to pop the delay.
*/
virtual bool try_interrupt(bool /*force*/)
{
// The default is for delays to be uninterruptible once started.
return false;
}
/**
*@return true if the delay involves using the item in this way (and
* therefore the item should not be messed with).
*/
virtual bool is_being_used(const item_def& /*item*/) const
{
return false;
}
/**
* @return the delay's name; used in debugging and for the interrupt_ option family.
*/
virtual const char* name() const = 0;
};
class EquipOnDelay : public Delay
{
item_def& equip;
equipment_slot slot;
bool was_prompted = false;
void start() override;
void tick() override
{
mprf(MSGCH_MULTITURN_ACTION, "You continue %s %s.",
get_verb(), equip.name(DESC_YOUR).c_str());
}
bool invalidated() override;
void finish() override;
public:
EquipOnDelay(int dur, item_def& item, equipment_slot _slot) :
Delay(dur), equip(item), slot(_slot)
{ }
bool try_interrupt(bool force = false) override;
const char* name() const override
{
return "equip_on";
}
bool is_being_used(const item_def& item) const override
{
return &item == &equip;
}
private:
const char* get_verb();
};
class EquipOffDelay : public Delay
{
item_def& equip;
bool was_prompted = false;
void start() override;
void tick() override
{
mprf(MSGCH_MULTITURN_ACTION, "You continue %s %s.",
get_verb(), equip.name(DESC_YOUR).c_str());
}
bool invalidated() override;
void finish() override;
public:
EquipOffDelay(int dur, item_def& item) :
Delay(dur), equip(item)
{ }
bool try_interrupt(bool force = false) override;
const char* name() const override
{
return "equip_off";
}
bool is_being_used(const item_def& item) const override
{
return &item == &equip;
}
private:
const char* get_verb();
};
class MemoriseDelay : public Delay
{
void start() override;
void tick() override
{
mprf(MSGCH_MULTITURN_ACTION, "You continue memorising.");
}
void finish() override;
public:
spell_type spell;
MemoriseDelay(int dur, spell_type sp) :
Delay(dur), spell{sp}
{ }
bool try_interrupt(bool /*force*/) override;
const char* name() const override
{
return "memorise";
}
};
class PasswallDelay : public Delay
{
coord_def dest;
void start() override;
void tick() override
{
mprf(MSGCH_MULTITURN_ACTION, "You continue meditating on the rock.");
}
void finish() override;
public:
PasswallDelay(int dur, coord_def pos) :
Delay(dur), dest{pos}
{ }
bool try_interrupt(bool /*force*/) override;
bool is_relocation() const override
{
return true;
}
const char* name() const override
{
return "passwall";
}
};
class DropItemDelay : public Delay
{
item_def& item;
void tick() override;
void finish() override;
public:
DropItemDelay(int dur, item_def& it) :
Delay(dur), item(it)
{ }
const char* name() const override
{
return "drop_item";
}
bool is_being_used(const item_def& item_) const override
{
return &item_ == &item;
}
};
struct SelItem;
class MultidropDelay : public Delay
{
vector<SelItem>& items;
bool invalidated() override;
void tick() override;
public:
MultidropDelay(int dur, vector<SelItem>& vec) :
Delay(dur), items(vec)
{ }
bool try_interrupt(bool /*force*/) override;
const char* name() const override
{
return "multidrop";
}
bool is_parent() const override
{
// Can spawn delay_drop_item
return true;
}
};
class AscendingStairsDelay : public Delay
{
void finish() override;
public:
AscendingStairsDelay(int dur) : Delay(dur)
{ }
bool try_interrupt(bool /*force*/) override;
bool is_stairs() const override
{
return true;
}
const char* name() const override
{
return "ascending_stairs";
}
};
class DescendingStairsDelay : public Delay
{
void finish() override;
public:
DescendingStairsDelay(int dur) : Delay(dur)
{ }
bool try_interrupt(bool /*force*/) override;
bool is_stairs() const override
{
return true;
}
const char* name() const override
{
return "descending_stairs";
}
};
// The run delays (run, travel, rest) have some common code that does not apply
// to any other ones.
class BaseRunDelay : public Delay
{
void handle() override;
virtual bool want_move() const = 0;
virtual bool want_clear_messages() const = 0;
virtual command_type move_cmd() const = 0;
protected:
bool unsafe_once = false;
public:
bool is_run() const override
{
return true;
}
bool is_parent() const override
{
// Interlevel travel can do upstairs/downstairs delays.
// Additionally, travel/rest can do autoeat.
return true;
}
bool try_interrupt(bool /*force*/) override;
BaseRunDelay() : Delay(1)
{ }
};
class RunDelay : public BaseRunDelay
{
bool want_move() const override
{
return true;
}
bool want_clear_messages() const override
{
return true;
}
command_type move_cmd() const override;
public:
RunDelay() : BaseRunDelay()
{ }
const char* name() const override
{
return "run";
}
};
class RestDelay : public BaseRunDelay
{
bool want_move() const override
{
return false;
}
bool want_autoeat() const override
{
return true;
}
bool want_clear_messages() const override
{
return false;
}
command_type move_cmd() const override;
public:
RestDelay() : BaseRunDelay()
{ }
bool is_resting() const override
{
return true;
}
const char* name() const override
{
return "rest";
}
};
class TravelDelay : public BaseRunDelay
{
bool want_move() const override
{
return true;
}
bool want_autoeat() const override
{
return true;
}
bool want_clear_messages() const override
{
return true;
}
command_type move_cmd() const override;
public:
TravelDelay(bool unsafe) : BaseRunDelay()
{
unsafe_once = unsafe;
}
const char* name() const override
{
return "travel";
}
};
class MacroDelay : public Delay
{
void handle() override;
public:
MacroDelay() : Delay(1)
{ }
bool try_interrupt(bool /*force*/) override;
bool is_parent() const override
{
// Lua macros can in theory perform any of the other delays,
// including travel; in practise travel still assumes there can be
// no parent delay.
return true;
}
bool is_macro() const override
{
return true;
}
const char* name() const override
{
//XXX: this is compared to in _userdef_interrupt_activity
return "macro";
}
};
class MacroProcessKeyDelay : public Delay
{
public:
MacroProcessKeyDelay() : Delay(1)
{ }
void handle() override
{
// If a Lua macro wanted Crawl to process a key normally, early exit.
return;
}
const char* name() const override
{
return "macro_process_key";
}
};
class ShaftSelfDelay : public Delay
{
void start() override;
void tick() override
{
mprf(MSGCH_MULTITURN_ACTION, "You continue digging a shaft.");
}
void finish() override;
public:
ShaftSelfDelay(int dur) : Delay(dur)
{ }
bool try_interrupt(bool /*force*/) override;
bool is_relocation() const override
{
return true;
}
const char* name() const override
{
return "shaft_self";
}
};
class TransformDelay : public Delay
{
transformation form;
const item_def *talisman;
bool was_prompted = false;
void start() override;
void tick() override;
bool invalidated() override;
void finish() override;
public:
TransformDelay(transformation f, const item_def *t) :
Delay(3), form(f), talisman(t)
{ }
bool try_interrupt(bool force = false) override;
const char* name() const override
{
return "transform";
}
};
class ImbueDelay : public Delay
{
bool was_prompted = false;
void start() override;
void tick() override
{
mprf(MSGCH_MULTITURN_ACTION, "You continue imbuing your servitor.");
}
void finish() override;
public:
ImbueDelay(int dur, spell_type _spell) : Delay(dur), spell(_spell)
{ }
bool try_interrupt(bool force = false) override;
const char* name() const override
{
return "imbue_servitor";
}
private:
spell_type spell;
};
class ImprintDelay : public Delay
{
void start() override;
void tick() override
{
mprf(MSGCH_MULTITURN_ACTION, "You continue imprinting.");
}
void finish() override;
public:
ImprintDelay(int dur, const item_def& _weapon) : Delay(dur), wpn(_weapon)
{ }
bool try_interrupt(bool force = false) override;
const char* name() const override
{
return "imprint_weapon";
}
private:
item_def wpn;
};
void push_delay(shared_ptr<Delay> delay);
template<typename T, typename... Args>
shared_ptr<Delay> start_delay(Args&&... args)
{
auto delay = make_shared<T>(std::forward<Args>(args)...);
push_delay(delay);
return delay;
}
void stop_delay(bool stop_stair_travel = false, bool force = false);
bool you_are_delayed();
shared_ptr<Delay> current_delay();
void handle_delay();
bool player_stair_delay();
bool already_learning_spell(int spell = -1);
void clear_macro_process_key_delay();
activity_interrupt get_activity_interrupt(const string &);
void run_macro(const char *macroname = nullptr);
void autotoggle_autopickup(bool off);
bool interrupt_activity(activity_interrupt ai,
const activity_interrupt_data &a
= activity_interrupt_data());
void monster_interrupt_message(activity_interrupt ai, const activity_interrupt_data &at);
|