polserver/pol-core/support/scripts/npc.em
turleypol e6abc8fcfe
Attackable item (#884)
* introduced Attackable wrapper class for opponents to be able to also
attack items

* changed set_opponent to use Attackable
moved first logic into Attackable

* added dynamic property which returns a pointer of the object instead of
a copy like the current imp.
needed to be able to eg store a vector

* send engage/disengage events
send hp status bar

* send attackable item flag in world item pkt

* apply damage for items + evid_damaged

* react to statrequests

* adapted is_attackable and do attack_effects

* fixed clear_opponent_of

* fixed clear_opponent_of

* allow attack pkt

* apply damage

* items need to keep track of the opponents to be able to cleanup on
destroy

* updated dynproperties

* updated dynprops a bit more.
made the structs trivial copyable
updated concept to not repeat the types

* run hitscript, cleanup

* listhostiles and attack_once accept now Attackable

* set opponent when dblclicked

* dont let hp underflow

* only attack if you are in warmode

* evid_opponent_moved for attackable items

* if its the same opponent dont send engaged events again
added test for listhostiles with two mobs

* allow attackable item for setopponent

* some tests npc vs item

* missing files

* fixed clang tidy complain

* test for enter/left area

* do not send hp updates while char gets created and not yet added to the
  world

* testclient fight packets

* client event constants

* added client tests for attacking npc and item

* increase damage

* removed leftover comment

* when an attackable item was destroyed the opponents where not correctly cleared

* orphan check for is_attackable

* moved statmsg for items

* init member

* moved send_hightlight back into if statement
check before dereferencing

* use range version of statmsg

* adapted em params

* comparison operator
made explicit constructors
for symmetry return damage in Item::apply_damage

* get rid of bools

* split attack method a bit

* use constants for F3 flag

* destroy item on hit if hp reaches 0 if no controlscript exists

* only toplevel items are attackable
small refactoring
more tests

* more tests

* even more tests

* docs
2026-07-30 20:27:36 +02:00

114 lines
4 KiB
Text

////////////////////////////////////////////////////////////////
//
// CONSTANTS
//
////////////////////////////////////////////////////////////////
// format-off
// Constants for texttype flags in the Say() and SayUC() functions
const SAY_TEXTTYPE_DEFAULT := "default";
const SAY_TEXTTYPE_WHISPER := "whisper";
const SAY_TEXTTYPE_YELL := "yell";
// Constant for Unicode Language flag in the SayUC() function
const SAY_LANG := "ENU";
// Constants for doevent flag in Say() and SayUC() functions
const SAY_DOEVENT_DISABLE := 0x0;
const SAY_DOEVENT_ENABLE := 0x1;
const FACE_NORMAL := 0x0;
const FACE_FORCE := 0x1;
// format-on
////////////////////////////////////////////////////////////////
//
// FUNCTIONS
//
////////////////////////////////////////////////////////////////
// SetAnchor: set a wander-anchor
// centerx, centery: the anchor-point
// distance_start: distance from center where boundary kicks in
// percent_subtract: percent chance per tile past the boundary that moving away will fail
SetAnchor( centerx, centery, distance_start, percent_subtract );
// Self(): return a mobileref to self
Self();
// Wander: walk, usually forward, sometimes turning
Wander();
// Face: takes an integer (0 - 7) or direction string: N, S, E, W, NW, NE, SW, SE
Face( direction, flags := FACE_NORMAL );
// N, S, E, W, NW, NE, SW, SE
// a boundingbox is okay, too
Move( direction );
// Move toward, or away from, something.
// When a pathfinding algorith exists, these functions will use if necessary.
// Puts the script to sleep for a period of time proportional to the NPC's agility.
// Note also, walking in range of your opponent may cause you to attack.
WalkToward( object );
WalkAwayFrom( object );
RunToward( object );
RunAwayFrom( object );
TurnToward( object, flags := FACE_NORMAL );
TurnAwayFrom( object, flags := FACE_NORMAL );
WalkTowardLocation( x, y );
WalkAwayFromLocation( x, y );
RunTowardLocation( x, y );
RunAwayFromLocation( x, y );
TurnTowardLocation( x, y, flags := FACE_NORMAL );
TurnAwayFromLocation( x, y, flags := FACE_NORMAL );
// Set your opponent. If you are in range (or are carrying
// a projectile weapon and have LOS), you will attack. If
// a player character is connected, the NPC will highlight.
// Implicitly sets war mode.
SetOpponent( attackable );
// SetWarMode: Usually used to leave warmode, but can be used
// to enter warmode independently of setting an opponent.
// Setting war mode to 0 clears your opponent.
SetWarMode( warmode );
// Instructs an npc to speak
// Texttype is the type of speech the npc will make (Whisper, Normal, Yell)
// If doevent is enabled, it will send a system event to other npcs.
Say( text, text_type := SAY_TEXTTYPE_DEFAULT, do_event := SAY_DOEVENT_DISABLE );
// Instructs an npc to speak in Unicode
// Texttype is the type of speech the npc will make (Whisper, Normal, Yell)
// If doevent is enabled, it will send a system event to other npcs.
// 'uc_text' is a String, or for backward compatibility an Array of 2-byte integers,
// where each integer is a Unicode character!
// 'langcode' is a 3-character "Originating Language" code
// e.g. ENG, ENU, CHT, DEU, FRA, JPN, RUS, KOR (etc??)
SayUC( uc_text, text_type := SAY_TEXTTYPE_DEFAULT, langcode := SAY_LANG, do_event := SAY_DOEVENT_DISABLE );
// * deprecated ( use Self().x, Self().y, Self().z ) - Do not use
position();
// Get a custom property. Equivalent to GetObjProperty( Self(), propertyname )
GetProperty( propertyname );
// Set a custom property.
// Equivalent to SetObjProperty( Self(), propertyname, propertyvalue )
SetProperty( propertyname, propertyvalue );
// Make a bounding box from an area string.
// An area string is a number of 'x1 y1 x2 y2' entries.
// "1 1 10 10 10 3 20 6" would create a walk area something like this:
// XXX
// XXXXXX
// XXX
MakeBoundingBox( areastring );
// IsLegalMove: Given your position, and a tentative move, would it
// fall within a bounding box?
IsLegalMove( move, boundingbox );
// CanMove: Given current position and direction, would it be possible to move there?
CanMove( direction );