3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
8 * See LICENSING which should be included
9 * along with this file for more details
12 /* Compiled through itemset.cpp */
14 cchar
*ToHitValueDescription
[] = {
15 "unbelievably inaccurate",
16 "extremely inaccurate",
22 "unbelievably accurate"
25 cchar
*StrengthValueDescription
[] = {
36 itemprototype::itemprototype (const itemprototype
*Base
, itemspawner Spawner
, itemcloner Cloner
, cchar
*ClassID
) :
42 Index
= protocontainer
<item
>::Add(this);
46 truth
itemdatabase::AllowRandomInstantiation () const { return !(Config
& S_LOCK_ID
); }
60 truth
item::IsOnGround () const { return Slot
[0]->IsOnGround(); }
61 truth
item::IsSimiliarTo (item
*Item
) const { return Item
->GetType() == GetType() && Item
->GetConfig() == GetConfig(); }
62 double item::GetBaseDamage () const { return sqrt(5e-5*GetWeaponStrength())+GetDamageBonus(); }
63 int item::GetBaseMinDamage () const { return int(GetBaseDamage()*0.75); }
64 int item::GetBaseMaxDamage () const { return int(GetBaseDamage()*1.25)+1; }
65 int item::GetBaseToHitValue () const { return int(10000.0/(1000+GetWeight())+GetTHVBonus()); }
66 int item::GetBaseBlockValue () const { return int((10000.0/(1000+GetWeight())+GetTHVBonus())*GetBlockModifier()/10000.0); }
67 truth
item::IsInCorrectSlot (int I
) const { return I
== RIGHT_WIELDED_INDEX
|| I
== LEFT_WIELDED_INDEX
; }
68 truth
item::IsInCorrectSlot () const { return IsInCorrectSlot(static_cast<gearslot
*>(*Slot
)->GetEquipmentIndex()); }
69 int item::GetEquipmentIndex () const { return static_cast<gearslot
*>(*Slot
)->GetEquipmentIndex(); }
70 int item::GetGraphicsContainerIndex () const { return GR_ITEM
; }
71 truth
item::IsBroken () const { return GetConfig () & BROKEN
; }
72 truth
item::IsFood() const { return DataBase
->Category
& FOOD
; }
73 cchar
*item::GetBreakVerb () const { return "breaks"; }
74 square
*item::GetSquareUnderEntity (int I
) const { return GetSquareUnder(I
); }
75 square
*item::GetSquareUnder (int I
) const { return Slot
[I
] ? Slot
[I
]->GetSquareUnder () : 0; }
76 lsquare
*item::GetLSquareUnder (int I
) const { return static_cast<lsquare
*>(Slot
[I
]->GetSquareUnder ()); }
77 void item::SignalStackAdd (stackslot
*StackSlot
, void (stack::*)(item
*, truth
)) { Slot
[0] = StackSlot
; }
78 truth
item::IsAnimated () const { return GraphicData
.AnimationFrames
> 1 || (Fluid
&& ShowFluids ()); }
79 truth
item::IsRusted () const { return MainMaterial
->GetRustLevel () != NOT_RUSTED
; }
80 truth
item::IsEatable (ccharacter
*Eater
) const { return GetConsumeMaterial(Eater
, &material::IsSolid
) && IsConsumable (); }
81 truth
item::IsDrinkable (ccharacter
*Eater
) const { return GetConsumeMaterial(Eater
, &material::IsLiquid
) && IsConsumable (); }
82 pixelpredicate
item::GetFluidPixelAllowedPredicate () const { return &rawbitmap::IsTransparent
; }
83 void item::Cannibalize () { Flags
|= CANNIBALIZED
; }
84 void item::SetMainMaterial (material
*NewMaterial
, int SpecialFlags
) { SetMaterial(MainMaterial
, NewMaterial
, GetDefaultMainVolume (), SpecialFlags
); }
85 void item::ChangeMainMaterial (material
*NewMaterial
, int SpecialFlags
) { ChangeMaterial(MainMaterial
, NewMaterial
, GetDefaultMainVolume (), SpecialFlags
); }
86 void item::InitMaterials (const materialscript
*M
, const materialscript
*, truth CUP
) { InitMaterials(M
->Instantiate (), CUP
); }
87 int item::GetMainMaterialRustLevel () const { return MainMaterial
->GetRustLevel(); }
90 item::item (citem
&Item
) :
94 DataBase(Item
.DataBase
),
99 SquaresUnder(Item
.SquaresUnder
),
100 LifeExpectancy(Item
.LifeExpectancy
),
101 ItemFlags(Item
.ItemFlags
)
103 Flags
&= ENTITY_FLAGS
|SQUARE_POSITION_BITS
;
104 ID
= game::CreateNewItemID(this);
105 CloneMotherID
= new idholder(Item
.ID
);
106 idholder
* TI
= CloneMotherID
;
108 for (idholder
* II
= Item
.CloneMotherID
; II
; II
= II
->Next
) TI
= TI
->Next
= new idholder(II
->ID
);
110 Slot
= new slot
*[SquaresUnder
];
111 for (int c
= 0; c
< SquaresUnder
; ++c
) Slot
[c
] = 0;
117 game::RemoveItemID(ID
);
120 for (int c
= 0; c
< /*SquaresUnder*/FluidCount
; ++c
) {
121 for (fluid
* F
= FP
[c
]; F
;) {
133 void item::Fly (character
*Thrower
, int Direction
, int Force
) {
134 int Range
= Force
*25/Max(sLong(sqrt(GetWeight())), 1);
135 lsquare
*LSquareUnder
= GetLSquareUnder();
137 LSquareUnder
->GetStack()->AddItem(this, false);
138 if (!Range
|| GetSquaresUnder() != 1) {
139 if (GetLSquareUnder()->GetRoom()) GetLSquareUnder()->GetRoom()->AddItemEffect(this);
142 if (Direction
== RANDOM_DIR
) Direction
= RAND()&7;
143 v2 StartingPos
= GetPos();
144 v2 Pos
= StartingPos
;
145 v2 DirVector
= game::GetMoveVector(Direction
);
146 truth Breaks
= false;
147 double BaseDamage
, BaseToHitValue
;
150 int Bonus
= Thrower
->IsHumanoid() ? Thrower
->GetCWeaponSkill(GetWeaponCategory())->GetBonus() : 1000;
151 BaseDamage
= sqrt(5e-12 * GetWeaponStrength() * Force
/ Range
) * Bonus
;
152 BaseToHitValue
= 10 * Bonus
* Thrower
->GetMoveEase() / (500 + GetWeight()) * Thrower
->GetAttribute(DEXTERITY
) * sqrt(2.5e-8 * Thrower
->GetAttribute(PERCEPTION
)) / Range
;
154 BaseDamage
= sqrt(5e-6 * GetWeaponStrength() * Force
/ Range
);
155 BaseToHitValue
= 10 * 100 / (500 + GetWeight()) / Range
;
158 for (RangeLeft
= Range
; RangeLeft
; --RangeLeft
) {
159 if (!GetLevel()->IsValidPos(Pos
+DirVector
)) break;
160 lsquare
*JustHit
= GetNearLSquare(Pos
+DirVector
);
161 if (!JustHit
->IsFlyable()) {
163 JustHit
->GetOLTerrain()->HasBeenHitByItem(Thrower
, this, int(BaseDamage
*sqrt(RangeLeft
)));
166 clock_t StartTime
= clock();
169 JustHit
->GetStack()->AddItem(this, false);
170 truth Draw
= game::OnScreen(JustHit
->GetPos()) && JustHit
->CanBeSeenByPlayer();
171 if (Draw
) game::DrawEverything();
172 if (JustHit
->GetCharacter()) {
173 int Damage
= int(BaseDamage
* sqrt(RangeLeft
));
174 double ToHitValue
= BaseToHitValue
*RangeLeft
;
175 int Returned
= HitCharacter(Thrower
, JustHit
->GetCharacter(), Damage
, ToHitValue
, Direction
);
176 if (Returned
== HIT
) Breaks
= true;
177 if (Returned
!= MISSED
) break;
179 if (Draw
) { while (clock()-StartTime
< 0.03 * CLOCKS_PER_SEC
); } //FIXME
182 if (Breaks
) ReceiveDamage(Thrower
, int(sqrt(GetWeight()*RangeLeft
) / 10), THROW
|PHYSICAL_DAMAGE
, Direction
);
183 if (Exists() && GetLSquareUnder()->GetRoom()) GetLSquareUnder()->GetRoom()->AddItemEffect(this);
187 int item::HitCharacter (character
*Thrower
, character
*Dude
, int Damage
, double ToHitValue
, int Direction
) {
188 if (Dude
->Catches(this)) return CATCHED
;
189 if (Thrower
&& !EffectIsGood()) Thrower
->Hostility(Dude
);
190 if (Dude
->DodgesFlyingItem(this, ToHitValue
)) {
191 if (Dude
->IsPlayer()) ADD_MESSAGE("%s misses you.", CHAR_NAME(DEFINITE
));
192 else if (Dude
->CanBeSeenByPlayer()) ADD_MESSAGE("%s misses %s.", CHAR_NAME(DEFINITE
), Dude
->CHAR_NAME(DEFINITE
));
195 Dude
->HasBeenHitByItem(Thrower
, this, Damage
, ToHitValue
, Direction
);
200 double item::GetWeaponStrength () const {
201 return GetFormModifier() * GetMainMaterial()->GetStrengthValue() * sqrt(GetMainMaterial()->GetWeight());
205 int item::GetStrengthRequirement () const {
206 double WeightTimesSize
= GetWeight() * GetSize();
207 return int(1.25e-10 * WeightTimesSize
* WeightTimesSize
);
211 truth
item::Apply (character
*Applier
) {
212 if (Applier
->IsPlayer()) ADD_MESSAGE("You can't apply this!");
217 /* Returns truth that tells whether the Polymorph really happened */
218 truth
item::Polymorph (character
*Polymorpher
, stack
*CurrentStack
) {
219 if (!IsPolymorphable()) return false;
220 if (Polymorpher
&& IsOnGround()) {
221 room
*Room
= GetRoom();
222 if (Room
) Room
->HostileAction(Polymorpher
);
224 if (GetSquarePosition() != CENTER
) {
225 stack
*Stack
= CurrentStack
->GetLSquareUnder()->GetStackOfAdjacentSquare(GetSquarePosition());
226 if (Stack
) CurrentStack
= Stack
;
228 CurrentStack
->AddItem(protosystem::BalancedCreateItem(0, MAX_PRICE
, ANY_CATEGORY
, 0, 0, 0, true));
235 /* Returns whether the Eater must stop eating the item */
236 truth
item::Consume (character
*Eater
, sLong Amount
) {
237 material
*ConsumeMaterial
= GetConsumeMaterial(Eater
);
238 if (!ConsumeMaterial
) return true;
239 if (Eater
->IsPlayer() && !(Flags
& CANNIBALIZED
) && Eater
->CheckCannibalism(ConsumeMaterial
)) {
240 game::DoEvilDeed(25);
241 ADD_MESSAGE("You feel that this was an evil deed.");
244 feuLong ID
= GetID();
245 material
*Garbage
= ConsumeMaterial
->EatEffect(Eater
, Amount
);
246 item
*NewConsuming
= GetID() ? this : game::SearchItem(ID
);
247 material
*NewConsumeMaterial
= NewConsuming
->GetConsumeMaterial(Eater
);
248 if (!NewConsuming
->Exists() || !NewConsumeMaterial
|| !NewConsumeMaterial
->IsSameAs(ConsumeMaterial
))
249 ConsumeMaterial
->FinishConsuming(Eater
);
251 return !NewConsuming
->Exists() || !NewConsumeMaterial
;
255 truth
item::CanBeEatenByAI (ccharacter
*Eater
) const {
256 material
*ConsumeMaterial
= GetConsumeMaterial(Eater
);
257 return (!Eater
->IsPet()
258 || !(Eater
->GetCommandFlags() & DONT_CONSUME_ANYTHING_VALUABLE
)
261 && ConsumeMaterial
&& ConsumeMaterial
->CanBeEatenByAI(Eater
);
265 void item::Save (outputfile
&SaveFile
) const {
266 SaveFile
<< (uShort
)GetType();
267 object::Save(SaveFile
);
268 SaveFile
<< (uShort
)0;
269 SaveFile
<< mIsStepedOn
;
270 SaveFile
<< (uShort
)GetConfig();
271 SaveFile
<< (uShort
)Flags
;
272 SaveFile
<< Size
<< ID
<< LifeExpectancy
<< ItemFlags
;
273 SaveLinkedList(SaveFile
, CloneMotherID
);
276 SaveFile
<< FluidCount
;
277 for (int c
= 0; c
< /*SquaresUnder*/FluidCount
; ++c
) SaveLinkedList(SaveFile
, Fluid
[c
]);
284 void item::Load (inputfile
&SaveFile
) {
285 object::Load(SaveFile
);
286 int ver
= ReadType
<uShort
>(SaveFile
);
287 if (ver
!= 0) ABORT("invalid item version in savefile: %d", ver
);
288 SaveFile
>> mIsStepedOn
;
289 databasecreator
<item
>::InstallDataBase(this, ReadType
<uShort
>(SaveFile
));
290 Flags
|= ReadType
<uShort
>(SaveFile
) & ~ENTITY_FLAGS
;
291 SaveFile
>> Size
>> ID
>> LifeExpectancy
>> ItemFlags
;
292 LoadLinkedList(SaveFile
, CloneMotherID
);
293 if (LifeExpectancy
) Enable();
294 game::AddItemID(this, ID
);
295 if (SaveFile
.Get()) {
296 SaveFile
>> FluidCount
;
297 Fluid
= new fluid
*[/*SquaresUnder*/FluidCount
];
298 for (int c
= 0; c
< /*SquaresUnder*/FluidCount
; ++c
) {
299 LoadLinkedList(SaveFile
, Fluid
[c
]);
300 for (fluid
*F
= Fluid
[c
]; F
; F
= F
->Next
) F
->SetMotherItem(this);
303 if (Fluid
) Fluid
= 0; //FIXME: MEMORY LEAK
309 void item::TeleportRandomly () {
310 if (GetSquaresUnder() == 1) {
312 lsquare
*Square
= GetNearLSquare(GetLevel()->GetRandomSquare());
313 MoveTo(Square
->GetStack());
314 if (Square
->CanBeSeenByPlayer()) ADD_MESSAGE("Suddenly %s appears!", CHAR_NAME(INDEFINITE
));
319 int item::GetStrengthValue () const {
320 return sLong(GetStrengthModifier()) * GetMainMaterial()->GetStrengthValue() / 2000;
324 void item::RemoveFromSlot () {
325 for (int c
= 0; c
< SquaresUnder
; ++c
) {
329 } catch (quitrequest
) {
339 void item::MoveTo (stack
*Stack
) {
341 Stack
->AddItem(this);
345 cchar
*item::GetItemCategoryName (sLong Category
) {
348 case HELMET
: return "Helmets";
349 case AMULET
: return "Amulets";
350 case CLOAK
: return "Cloaks";
351 case BODY_ARMOR
: return "Body armors";
352 case WEAPON
: return "Weapons";
353 case SHIELD
: return "Shields";
354 case RING
: return "Rings";
355 case GAUNTLET
: return "Gauntlets";
356 case BELT
: return "Belts";
357 case BOOT
: return "Boots";
358 case FOOD
: return "Food";
359 case POTION
: return "Potions";
360 case SCROLL
: return "Scrolls";
361 case BOOK
: return "Books";
362 case WAND
: return "Wands";
363 case TOOL
: return "Tools";
364 case VALUABLE
: return "Valuables";
365 case MISC
: return "Miscellaneous items";
371 int item::GetResistance (int Type
) const {
372 switch (Type
&0xFFF) {
373 case PHYSICAL_DAMAGE
: return GetStrengthValue();
377 case MUSTARD_GAS_DAMAGE
:
379 case FIRE
: return GetFireResistance();
380 case POISON
: return GetPoisonResistance();
381 case ELECTRICITY
: return GetElectricityResistance();
382 case ACID
: return GetAcidResistance();
384 ABORT("Resistance lack detected!");
389 truth
item::Open (character
*Char
) {
390 if (Char
->IsPlayer()) ADD_MESSAGE("You can't open %s.", CHAR_NAME(DEFINITE
));
395 item
*itemprototype::SpawnAndLoad (inputfile
&SaveFile
) const {
396 item
*Item
= Spawner(0, LOAD
);
397 Item
->Load(SaveFile
);
398 Item
->CalculateAll();
403 void item::LoadDataBaseStats () {
404 SetSize(GetDefaultSize());
408 void item::Initialize (int NewConfig
, int SpecialFlags
) {
409 CalculateSquaresUnder();
410 Slot
= new slot
*[SquaresUnder
];
411 for (int c
= 0; c
< SquaresUnder
; ++c
) Slot
[c
] = 0;
412 if (!(SpecialFlags
& LOAD
)) {
413 ID
= game::CreateNewItemID(this);
414 databasecreator
<item
>::InstallDataBase(this, NewConfig
);
416 RandomizeVisualEffects();
417 Flags
|= CENTER
<< SQUARE_POSITION_SHIFT
;
418 if (!(SpecialFlags
& NO_MATERIALS
)) GenerateMaterials();
420 if (!(SpecialFlags
& LOAD
)) PostConstruct();
421 if (!(SpecialFlags
& (LOAD
|NO_MATERIALS
))) {
423 if (!(SpecialFlags
& NO_PIC_UPDATE
)) UpdatePictures();
428 truth
item::ShowMaterial () const {
429 if (GetMainMaterialConfig().Size
== 1) return GetMainMaterial()->GetConfig() != GetMainMaterialConfig()[0];
430 //FIXME: gum solution
432 // never show the material for 'bone bone'
433 if (GetMainMaterial()->GetConfig() == BONE
) return false;
439 sLong
item::GetBlockModifier() const
442 return GetSize() * GetRoundness() << 1;
444 return GetSize() * GetRoundness() << 2;
447 truth
item::CanBeSeenByPlayer() const
449 return CanBeSeenBy(PLAYER
);
452 truth
item::CanBeSeenBy(ccharacter
* Who
) const
454 for(int c
= 0; c
< SquaresUnder
; ++c
)
455 if(Slot
[c
] && Slot
[c
]->CanBeSeenBy(Who
))
458 return Who
->IsPlayer() && game::GetSeeWholeMapCheatMode();
461 festring
item::GetDescription(int Case
) const
463 if(CanBeSeenByPlayer())
464 return GetName(Case
);
466 return CONST_S("something");
469 void item::SignalVolumeAndWeightChange()
471 CalculateVolumeAndWeight();
473 for(int c
= 0; c
< SquaresUnder
; ++c
)
475 Slot
[c
]->SignalVolumeAndWeightChange();
478 void item::CalculateVolumeAndWeight()
482 for(int c
= 0; c
< GetMaterials(); ++c
)
484 cmaterial
* Material
= GetMaterial(c
);
488 Volume
+= Material
->GetVolume();
489 Weight
+= Material
->GetWeight();
494 void item::SignalEmitationIncrease(col24 EmitationUpdate
)
496 if(game::CompareLights(EmitationUpdate
, Emitation
) > 0)
498 game::CombineLights(Emitation
, EmitationUpdate
);
500 for(int c
= 0; c
< SquaresUnder
; ++c
)
502 Slot
[c
]->SignalEmitationIncrease(EmitationUpdate
);
506 void item::SignalEmitationDecrease(col24 EmitationUpdate
)
508 if(game::CompareLights(EmitationUpdate
, Emitation
) >= 0 && Emitation
)
510 col24 Backup
= Emitation
;
511 CalculateEmitation();
513 if(Backup
!= Emitation
)
514 for(int c
= 0; c
< SquaresUnder
; ++c
)
516 Slot
[c
]->SignalEmitationDecrease(EmitationUpdate
);
520 void item::CalculateAll()
522 CalculateVolumeAndWeight();
523 CalculateEmitation();
526 /* Temporary and buggy. */
528 void item::WeaponSkillHit(int Hits
)
530 if(Slot
[0] && Slot
[0]->IsGearSlot())
531 static_cast<arm
*>(static_cast<gearslot
*>(*Slot
)->GetBodyPart())->WieldedSkillHit(Hits
);
534 /* Returns 0 if item cannot be cloned */
536 item
* item::Duplicate(feuLong Flags
)
538 if(!(Flags
& IGNORE_PROHIBITIONS
)
539 && ((!(Flags
& MIRROR_IMAGE
) && !CanBeCloned())
540 || (Flags
& MIRROR_IMAGE
&& (!CanBeMirrored()
542 && !(MainMaterial
->GetCommonFlags() & CAN_BE_MIRRORED
))
543 || (GetSecondaryMaterial()
544 && !(GetSecondaryMaterial()->GetCommonFlags() & CAN_BE_MIRRORED
))))))
547 item
* Clone
= GetProtoType()->Clone(this);
549 if(Flags
& MIRROR_IMAGE
)
550 Clone
->SetLifeExpectancy(Flags
>> LE_BASE_SHIFT
& LE_BASE_RANGE
,
551 Flags
>> LE_RAND_SHIFT
& LE_RAND_RANGE
);
553 idholder
* I
= new idholder(ID
);
554 I
->Next
= CloneMotherID
;
556 game::RemoveItemID(ID
);
557 ID
= game::CreateNewItemID(this);
558 Clone
->UpdatePictures();
562 void item::AddInventoryEntry(ccharacter
*, festring
& Entry
, int Amount
, truth ShowSpecialInfo
) const
565 AddName(Entry
, INDEFINITE
);
568 Entry
<< Amount
<< ' ';
569 AddName(Entry
, PLURAL
);
573 Entry
<< " [" << GetWeight() * Amount
<< "g]";
576 const itemdatabase
* itemprototype::ChooseBaseForConfig(itemdatabase
** TempConfig
, int Configs
, int ConfigNumber
)
578 if(!(ConfigNumber
& BROKEN
))
582 ConfigNumber
^= BROKEN
;
584 for(int c
= 0; c
< Configs
; ++c
)
585 if(TempConfig
[c
]->Config
== ConfigNumber
)
586 return TempConfig
[c
];
592 truth
item::ReceiveDamage(character
* Damager
, int Damage
, int Type
, int Dir
)
594 if(CanBeBroken() && !IsBroken() && Type
& (PHYSICAL_DAMAGE
|SOUND
|ENERGY
|ACID
))
596 int StrengthValue
= GetStrengthValue();
601 if(Damage
> StrengthValue
<< 2 && RAND() & 3 && RAND() % (25 * Damage
/ StrengthValue
) >= 100)
608 if(Type
& ACID
&& IsBroken() && IsDestroyable(Damager
))
610 int StrengthValue
= GetStrengthValue();
615 if(Damage
> StrengthValue
<< 4 && !(RAND() & 3) && RAND() % (100 * Damage
/ StrengthValue
) >= 100)
617 Destroy(Damager
, Dir
);
625 void itemdatabase::InitDefaults(const itemprototype
* NewProtoType
, int NewConfig
)
628 ProtoType
= NewProtoType
;
631 if(NewConfig
& BROKEN
)
633 if(Adjective
.GetSize())
634 Adjective
.Insert(0, "broken ");
636 Adjective
= CONST_S("broken");
640 StrengthModifier
>>= 1;
644 sLong
item::GetNutritionValue() const
648 for(int c
= 0; c
< GetMaterials(); ++c
)
650 NV
+= GetMaterial(c
)->GetTotalNutritionValue();
655 void item::SignalSpoil(material
*)
660 if(CanBeSeenByPlayer())
661 ADD_MESSAGE("%s spoils completely.", GetExtendedDescription().CStr());
663 truth Equipped
= PLAYER
->Equips(this);
667 game::AskForEscPress(CONST_S("Equipment destroyed!"));
670 item
* item::DuplicateToStack(stack
* CurrentStack
, feuLong Flags
)
672 item
* Duplicated
= Duplicate(Flags
);
677 CurrentStack
->AddItem(Duplicated
);
681 truth
item::CanBePiledWith(citem
* Item
, ccharacter
* Viewer
) const
683 return (GetType() == Item
->GetType()
684 && GetConfig() == Item
->GetConfig()
685 && ItemFlags
== Item
->ItemFlags
686 && (WeightIsIrrelevant() || Weight
== Item
->Weight
)
687 && MainMaterial
->IsSameAs(Item
->MainMaterial
)
688 && MainMaterial
->GetSpoilLevel() == Item
->MainMaterial
->GetSpoilLevel()
689 && MainMaterial
->GetRustLevel() == Item
->MainMaterial
->GetRustLevel()
690 && Viewer
->GetCWeaponSkillLevel(this) == Viewer
->GetCWeaponSkillLevel(Item
)
691 && Viewer
->GetSWeaponSkillLevel(this) == Viewer
->GetSWeaponSkillLevel(Item
)
692 && !Fluid
&& !Item
->Fluid
693 && !LifeExpectancy
== !Item
->LifeExpectancy
);
696 void item::Break(character
* Breaker
, int)
698 if(CanBeSeenByPlayer())
699 ADD_MESSAGE("%s %s.", GetExtendedDescription().CStr(), GetBreakVerb());
701 if(Breaker
&& IsOnGround())
703 room
* Room
= GetRoom();
706 Room
->HostileAction(Breaker
);
709 item
* Broken
= GetProtoType()->Clone(this);
710 Broken
->SetConfig(GetConfig() | BROKEN
);
711 Broken
->SetSize(Broken
->GetSize() >> 1);
712 DonateFluidsTo(Broken
);
714 DonateSlotTo(Broken
);
717 if(PLAYER
->Equips(Broken
))
718 game::AskForEscPress(CONST_S("Equipment broken!"));
723 MainMaterial
->Be(ItemFlags
);
725 if (Exists() && LifeExpectancy
) {
726 if (LifeExpectancy
== 1) {
727 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s disappears.", GetExtendedDescription().CStr());
728 truth Equipped
= PLAYER
->Equips(this);
730 if (Equipped
) game::AskForEscPress(CONST_S("Equipment destroyed!"));
737 int item::GetOfferValue(int Receiver
) const
741 int OfferValue
= int(sqrt(GetTruePrice()));
743 if(Receiver
== GetAttachedGod())
751 void item::SignalEnchantmentChange()
753 for(int c
= 0; c
< SquaresUnder
; ++c
)
755 Slot
[c
]->SignalEnchantmentChange();
758 sLong
item::GetEnchantedPrice(int Enchantment
) const
760 return !PriceIsProportionalToEnchantment() ? item::GetPrice() : Max
<int>(item::GetPrice() * Enchantment
* Enchantment
, 0);
769 Fixed
= GetProtoType()->Clone(this);
770 Fixed
->SetConfig(GetConfig() ^ BROKEN
);
771 Fixed
->SetSize(Fixed
->GetSize() << 1);
772 DonateFluidsTo(Fixed
);
781 void item::DonateSlotTo(item
* Item
)
785 Slot
[0]->DonateTo(Item
);
788 for(int c
= 1; c
< SquaresUnder
; ++c
)
797 int item::GetSpoilLevel() const
799 return MainMaterial
->GetSpoilLevel();
802 void item::SignalSpoilLevelChange(material
*)
804 if(!IsAnimated() && GetSpoilLevel() && Slot
[0] && Slot
[0]->IsVisible())
805 for(int c
= 0; c
< SquaresUnder
; ++c
)
806 GetSquareUnder(c
)->IncStaticAnimatedEntities();
808 SignalVolumeAndWeightChange(); // gum
812 truth
item::AllowSpoil() const
816 lsquare
* Square
= GetLSquareUnder();
817 int RoomNumber
= Square
->GetRoomIndex();
818 return !RoomNumber
|| Square
->GetLevel()->GetRoom(RoomNumber
)->AllowSpoil(this);
824 void item::ResetSpoiling()
826 for(int c
= 0; c
< GetMaterials(); ++c
)
828 GetMaterial(c
)->ResetSpoiling();
831 cchar
* item::GetBaseToHitValueDescription() const
833 if(GetBaseToHitValue() < 10)
834 return ToHitValueDescription
[Min(GetBaseToHitValue(), 6)];
836 return ToHitValueDescription
[7];
839 cchar
* item::GetBaseBlockValueDescription() const
841 if(GetBaseBlockValue() < 20)
842 return ToHitValueDescription
[Min(GetBaseBlockValue() >> 1, 6)];
844 return ToHitValueDescription
[7];
847 cchar
* item::GetStrengthValueDescription() const
849 int SV
= GetStrengthValue();
852 return StrengthValueDescription
[0];
854 return StrengthValueDescription
[1];
856 return StrengthValueDescription
[2];
858 return StrengthValueDescription
[3];
860 return StrengthValueDescription
[4];
862 return StrengthValueDescription
[5];
864 return StrengthValueDescription
[6];
867 void item::SpecialGenerationHandler()
870 Slot
[0]->AddFriendItem(Duplicate());
873 void item::SortAllItems(const sortdata
& SortData
) const
875 if(SortData
.Sorter
== 0 || (this->*SortData
.Sorter
)(SortData
.Character
))
876 SortData
.AllItems
.push_back(const_cast<item
*>(this));
879 int item::GetAttachedGod() const
881 return DataBase
->AttachedGod
? DataBase
->AttachedGod
: MainMaterial
->GetAttachedGod();
884 sLong
item::GetMaterialPrice() const
886 return MainMaterial
->GetRawPrice();
889 sLong
item::GetTruePrice() const
894 sLong Price
= Max(GetPrice(), GetMaterialPrice());
897 Price
= Price
* (100 - GetMaxSpoilPercentage()) / 500;
904 void item::AddAttackInfo(felist
& List
) const
906 festring
Entry(40, ' ');
907 Entry
<< int(GetWeight());
909 Entry
<< int(GetSize());
911 Entry
<< int(GetStrengthRequirement());
913 Entry
<< GetBaseMinDamage() << '-' << GetBaseMaxDamage();
914 List
.AddEntry(Entry
, LIGHT_GRAY
);
917 void item::AddMiscellaneousInfo(felist
& List
) const
919 festring
Entry(40, ' ');
920 Entry
<< int(GetTruePrice());
922 Entry
<< GetOfferValue(0);
924 Entry
<< int(GetNutritionValue());
925 List
.AddEntry(Entry
, LIGHT_GRAY
);
931 void item::PreProcessForBone () {
936 game::RemoveItemID(ID
);
938 game::AddItemID(this, ID
);
944 void item::PostProcessForBone () {
945 boneidmap::iterator BI
= game::GetBoneItemIDMap().find(-ID
);
946 game::RemoveItemID(ID
);
948 if (BI
== game::GetBoneItemIDMap().end()) {
949 feuLong NewID
= game::CreateNewItemID(this);
950 game::GetBoneItemIDMap().insert(std::make_pair(-ID
, NewID
));
953 if (game::SearchItem(BI
->second
)) {
955 game::AddItemID(this, ID
);
958 for (idholder
* I
= CloneMotherID
; I
; I
= I
->Next
) {
959 BI
= game::GetBoneItemIDMap().find(I
->ID
);
960 if (BI
== game::GetBoneItemIDMap().end()) {
961 feuLong NewCloneMotherID
= game::CreateNewItemID(0);
962 game::GetBoneItemIDMap().insert(std::make_pair(I
->ID
, NewCloneMotherID
));
963 I
->ID
= NewCloneMotherID
;
971 void item::SetConfig(int NewConfig
, int SpecialFlags
)
973 databasecreator
<item
>::InstallDataBase(this, NewConfig
);
976 if(!(SpecialFlags
& NO_PIC_UPDATE
))
980 god
* item::GetMasterGod() const
982 return game::GetGod(GetConfig());
985 int itemprototype::CreateSpecialConfigurations(itemdatabase
** TempConfig
, int Configs
, int Level
)
990 if(TempConfig
[0]->CreateDivineConfigurations
)
991 Configs
= databasecreator
<item
>::CreateDivineConfigurations(this, TempConfig
, Configs
);
995 if(TempConfig
[0]->CreateLockConfigurations
)
997 const item::database
*const* KeyConfigData
= key::ProtoType
.GetConfigData();
998 int KeyConfigSize
= key::ProtoType
.GetConfigSize();
999 int OldConfigs
= Configs
;
1001 for(int c1
= 0; c1
< OldConfigs
; ++c1
)
1002 if(!TempConfig
[c1
]->IsAbstract
)
1004 int BaseConfig
= TempConfig
[c1
]->Config
;
1005 int NewConfig
= BaseConfig
| BROKEN_LOCK
;
1006 itemdatabase
* ConfigDataBase
= new itemdatabase(*TempConfig
[c1
]);
1007 ConfigDataBase
->InitDefaults(this, NewConfig
);
1008 ConfigDataBase
->PostFix
<< "with a broken lock";
1009 ConfigDataBase
->Possibility
= 0;
1010 TempConfig
[Configs
++] = ConfigDataBase
;
1012 for(int c2
= 0; c2
< KeyConfigSize
; ++c2
)
1014 NewConfig
= BaseConfig
| KeyConfigData
[c2
]->Config
;
1015 ConfigDataBase
= new itemdatabase(*TempConfig
[c1
]);
1016 ConfigDataBase
->InitDefaults(this, NewConfig
);
1017 ConfigDataBase
->PostFix
<< "with ";
1019 if(KeyConfigData
[c2
]->UsesLongAdjectiveArticle
)
1020 ConfigDataBase
->PostFix
<< "an ";
1022 ConfigDataBase
->PostFix
<< "a ";
1024 ConfigDataBase
->PostFix
<< KeyConfigData
[c2
]->Adjective
<< " lock";
1025 ConfigDataBase
->Possibility
= 0;
1026 TempConfig
[Configs
++] = ConfigDataBase
;
1034 void item::Draw(blitdata
& BlitData
) const
1036 cint AF
= GraphicData
.AnimationFrames
;
1037 cint F
= !(BlitData
.CustomData
& ALLOW_ANIMATE
) || AF
== 1 ? 0 : GET_TICK() & (AF
- 1);
1038 cbitmap
* P
= GraphicData
.Picture
[F
];
1040 if(BlitData
.CustomData
& ALLOW_ALPHA
)
1041 P
->AlphaLuminanceBlit(BlitData
);
1043 P
->LuminanceMaskedBlit(BlitData
);
1045 if(Fluid
&& ShowFluids())
1046 DrawFluids(BlitData
);
1049 v2
item::GetLargeBitmapPos(v2 BasePos
, int I
) const
1051 cint SquareIndex
= I
? I
/ (GraphicData
.AnimationFrames
>> 2) : 0;
1052 return v2(SquareIndex
& 1 ? BasePos
.X
+ 16 : BasePos
.X
, SquareIndex
& 2 ? BasePos
.Y
+ 16 : BasePos
.Y
);
1055 void item::LargeDraw(blitdata
& BlitData
) const
1057 cint TrueAF
= GraphicData
.AnimationFrames
>> 2;
1058 cint SquareIndex
= BlitData
.CustomData
& SQUARE_INDEX_MASK
;
1059 cint F
= !(BlitData
.CustomData
& ALLOW_ANIMATE
) ? SquareIndex
* TrueAF
: SquareIndex
* TrueAF
+ (GET_TICK() & (TrueAF
- 1));
1060 cbitmap
* P
= GraphicData
.Picture
[F
];
1062 if(BlitData
.CustomData
& ALLOW_ALPHA
)
1063 P
->AlphaLuminanceBlit(BlitData
);
1065 P
->LuminanceMaskedBlit(BlitData
);
1068 void item::DonateIDTo(item
* Item
)
1070 game::RemoveItemID(Item
->ID
);
1071 game::UpdateItemID(Item
, ID
);
1076 void item::SignalRustLevelChange()
1078 SignalVolumeAndWeightChange();
1080 SendNewDrawAndMemorizedUpdateRequest();
1083 const rawbitmap
* item::GetRawPicture() const
1085 return igraph::GetRawGraphic(GetGraphicsContainerIndex());
1088 void item::RemoveFluid(fluid
*ToBeRemoved
) {
1089 truth WasAnimated
= IsAnimated();
1090 truth HasFluids
= false;
1092 if (Fluid
&& ToBeRemoved
) {
1093 for (int c
= 0; c
< /*SquaresUnder*/FluidCount
; ++c
) {
1094 fluid
*F
= Fluid
[c
];
1096 if (F
== ToBeRemoved
) {
1101 for (F
= F
->Next
; F
; LF
= F
, F
= F
->Next
) if (F
== ToBeRemoved
) { LF
->Next
= F
->Next
; break; }
1103 if (Fluid
[c
]) HasFluids
= true;
1107 if (!HasFluids
&& Fluid
) {
1110 if (!IsAnimated() != !WasAnimated
&& Slot
[0]->IsVisible()) GetSquareUnder()->DecStaticAnimatedEntities();
1112 if (ToBeRemoved
) SignalEmitationDecrease(ToBeRemoved
->GetEmitation());
1113 SignalVolumeAndWeightChange();
1117 void item::RemoveAllFluids () {
1119 for (int c
= 0; c
< /*SquaresUnder*/FluidCount
; ) {
1120 //fprintf(stderr, "c: %d; SquaresUnder: %d\n", c, SquaresUnder);
1121 fluid
*F
= Fluid
[c
];
1134 void item::AddFluid (liquid
*ToBeAdded
, festring LocationName
, int SquareIndex
, truth IsInside
) {
1135 truth WasAnimated
= IsAnimated();
1137 if (SquareIndex
< 0) ABORT("item::AddFluid(): invalid SquareIndex: %d", SquareIndex
);
1140 fluid
*F
= Fluid
[SquareIndex
];
1142 if (SquareIndex
>= FluidCount
) ABORT("item::AddFluid(): invalid SquareIndex: %d", SquareIndex
);
1144 Fluid
[SquareIndex
] = new fluid(ToBeAdded
, this, LocationName
, IsInside
);
1149 if (ToBeAdded
->IsSameAs(F
->GetLiquid())) {
1150 F
->AddLiquidAndVolume(ToBeAdded
->GetVolume());
1157 LF
->Next
= new fluid(ToBeAdded
, this, LocationName
, IsInside
);
1160 FluidCount
= SquaresUnder
;
1161 Fluid
= new fluid
*[/*SquaresUnder*/FluidCount
];
1162 if (SquareIndex
>= FluidCount
) ABORT("item::AddFluid(): invalid SquareIndex: %d", SquareIndex
);
1163 memset(Fluid
, 0, SquaresUnder
*sizeof(fluid
*));
1164 Fluid
[SquareIndex
] = new fluid(ToBeAdded
, this, LocationName
, IsInside
);
1168 SignalVolumeAndWeightChange();
1169 SignalEmitationIncrease(ToBeAdded
->GetEmitation());
1172 if (!IsAnimated() != !WasAnimated
&& Slot
[0]->IsVisible()) {
1173 GetSquareUnder()->IncStaticAnimatedEntities();
1175 SendNewDrawAndMemorizedUpdateRequest();
1179 void item::SendNewDrawAndMemorizedUpdateRequest() const
1181 if(!game::IsInWilderness())
1182 for(int c
= 0; c
< SquaresUnder
; ++c
)
1185 lsquare
* Square
= GetLSquareUnder(c
);
1186 Square
->SendNewDrawRequest();
1187 Square
->SendMemorizedUpdateRequest();
1191 void item::CalculateEmitation()
1193 object::CalculateEmitation();
1196 for(int c
= 0; c
< /*SquaresUnder*/FluidCount
; ++c
)
1197 for(const fluid
* F
= Fluid
[c
]; F
; F
= F
->Next
)
1198 game::CombineLights(Emitation
, F
->GetEmitation());
1201 void item::FillFluidVector (fluidvector
&Vector
, int SquareIndex
) const {
1203 if (SquareIndex
< 0 || SquareIndex
>= FluidCount
) ABORT("item::FillFluidVector(): invalid SquareIndex: %d\n", SquareIndex
);
1204 for (fluid
*F
= Fluid
[SquareIndex
]; F
; F
= F
->Next
) Vector
.push_back(F
);
1208 void item::SpillFluid(character
*, liquid
* Liquid
, int SquareIndex
)
1210 if(AllowFluids() && Liquid
->GetVolume())
1211 AddFluid(Liquid
, "", SquareIndex
, false);
1216 void item::TryToRust (sLong LiquidModifier
) {
1217 if (MainMaterial
->TryToRust(LiquidModifier
)) {
1218 if (CanBeSeenByPlayer()) {
1219 if (MainMaterial
->GetRustLevel() == NOT_RUSTED
) ADD_MESSAGE("%s rusts.", CHAR_NAME(DEFINITE
));
1220 else ADD_MESSAGE("%s rusts more.", CHAR_NAME(DEFINITE
));
1222 MainMaterial
->SetRustLevel(MainMaterial
->GetRustLevel() + 1);
1226 void item::CheckFluidGearPictures(v2 ShadowPos
, int SpecialFlags
, truth BodyArmor
)
1229 for(fluid
* F
= Fluid
[0]; F
; F
= F
->Next
)
1230 F
->CheckGearPicture(ShadowPos
, SpecialFlags
, BodyArmor
);
1233 void item::DrawFluidGearPictures(blitdata
& BlitData
, int SpecialFlags
) const
1236 for(const fluid
* F
= Fluid
[0]; F
; F
= F
->Next
)
1237 F
->DrawGearPicture(BlitData
, SpecialFlags
);
1240 void item::DrawFluidBodyArmorPictures(blitdata
& BlitData
, int SpecialFlags
) const
1243 for(const fluid
* F
= Fluid
[0]; F
; F
= F
->Next
)
1244 F
->DrawBodyArmorPicture(BlitData
, SpecialFlags
);
1247 void item::DrawFluids(blitdata
& BlitData
) const
1249 cint SquareIndex
= BlitData
.CustomData
& SQUARE_INDEX_MASK
;
1251 for(const fluid
* F
= Fluid
[SquareIndex
]; F
; F
= F
->Next
)
1255 void item::ReceiveAcid(material
*, cfestring
&, sLong Modifier
)
1257 if(GetMainMaterial()->GetInteractionFlags() & CAN_DISSOLVE
)
1259 int Damage
= Modifier
/ 1000;
1263 Damage
+= RAND() % Damage
;
1264 ReceiveDamage(0, Damage
, ACID
);
1269 void item::DonateFluidsTo(item
* Item
)
1272 for(int c
= 0; c
< GetSquaresUnder(); ++c
)
1273 for(fluid
* F
= Fluid
[c
]; F
; F
= F
->Next
)
1275 liquid
* Liquid
= F
->GetLiquid();
1276 Item
->AddFluid(Liquid
->SpawnMoreLiquid(Liquid
->GetVolume()), F
->GetLocationName(), c
, F
->IsInside());
1280 void item::Destroy(character
* Destroyer
, int)
1282 if(CanBeSeenByPlayer())
1283 ADD_MESSAGE("%s is destroyed.", GetExtendedDescription().CStr());
1285 if(Destroyer
&& IsOnGround())
1287 room
* Room
= GetRoom();
1290 Room
->HostileAction(Destroyer
);
1293 truth Equipped
= PLAYER
->Equips(this);
1298 game::AskForEscPress(CONST_S("Equipment destroyed!"));
1301 void item::RemoveRust()
1303 for(int c
= 0; c
< GetMaterials(); ++c
)
1305 GetMaterial(c
)->SetRustLevel(NOT_RUSTED
);
1308 void item::SetSpoilPercentage(int Value
)
1310 for(int c
= 0; c
< GetMaterials(); ++c
)
1312 material
* Material
= GetMaterial(c
);
1314 if(Material
&& Material
->CanSpoil())
1315 Material
->SetSpoilCounter(Material
->GetSpoilModifier() * Value
/ 100);
1319 void item::RedistributeFluids()
1322 for(int c
= 0; c
< GetSquaresUnder(); ++c
)
1323 for(fluid
* F
= Fluid
[c
]; F
; F
= F
->Next
)
1327 material
* item::GetConsumeMaterial(ccharacter
* Consumer
, materialpredicate Predicate
) const
1329 return (MainMaterial
->*Predicate
)() && Consumer
->CanConsume(MainMaterial
) ? MainMaterial
: 0;
1332 /* The parameter can only be MainMaterial */
1334 material
* item::RemoveMaterial(material
*)
1341 void item::InitMaterials(material
* FirstMaterial
, truth CallUpdatePictures
)
1343 InitMaterial(MainMaterial
, FirstMaterial
, GetDefaultMainVolume());
1344 SignalVolumeAndWeightChange();
1346 if(CallUpdatePictures
)
1350 void item::GenerateMaterials()
1352 int Chosen
= RandomizeMaterialConfiguration();
1353 const fearray
<sLong
>& MMC
= GetMainMaterialConfig();
1354 InitMaterial(MainMaterial
,
1355 MAKE_MATERIAL(MMC
.Data
[MMC
.Size
== 1 ? 0 : Chosen
]),
1356 GetDefaultMainVolume());
1359 void item::SignalSquarePositionChange(int Position
)
1361 Flags
&= ~SQUARE_POSITION_BITS
;
1362 Flags
|= Position
<< SQUARE_POSITION_SHIFT
;
1365 truth
item::Read(character
* Reader
)
1367 Reader
->StartReading(this, GetReadDifficulty());
1371 truth
item::CanBeHardened(ccharacter
*) const
1373 return MainMaterial
->GetHardenedMaterial(this) != NONE
;
1376 void item::SetLifeExpectancy(int Base
, int RandPlus
)
1378 LifeExpectancy
= RandPlus
> 1 ? Base
+ RAND_N(RandPlus
) : Base
;
1382 truth
item::IsVeryCloseToSpoiling() const
1384 for(int c
= 0; c
< GetMaterials(); ++c
)
1385 if(GetMaterial(c
) && !GetMaterial(c
)->IsVeryCloseToSpoiling())
1391 truth
item::IsValuable() const
1393 if(DataBase
->IsValuable
)
1396 for(int c
= 0; c
< GetMaterials(); ++c
)
1398 material
* M
= GetMaterial(c
);
1400 if(M
&& M
->GetCommonFlags() & IS_VALUABLE
)
1407 int item::GetHinderVisibilityBonus(ccharacter
* Char
) const
1411 if(GetGearStates() & INFRA_VISION
1412 && !Char
->TemporaryStateIsActivated(INFRA_VISION
))
1415 if(GetGearStates() & ESP
1416 && !Char
->TemporaryStateIsActivated(ESP
))
1419 if(!game::IsDark(GetEmitation()))
1425 sLong
item::GetFixPrice() const
1427 item
* Clone
= GetProtoType()->Clone(this);
1428 Clone
= Clone
->Fix();
1429 Clone
->RemoveRust();
1430 sLong FixPrice
= Clone
->GetTruePrice();
1431 Clone
->SendToHell();
1432 return Max(sLong(3.5 * sqrt(FixPrice
)), 10);
1435 void item::AddTrapName(festring
& String
, int Amount
) const
1438 AddName(String
, DEFINITE
);
1441 String
<< Amount
<< ' ';
1442 AddName(String
, PLURAL
);
1446 truth
item::Spoils() const
1448 for(int c
= 0; c
< GetMaterials(); ++c
)
1450 cmaterial
* Material
= GetMaterial(c
);
1452 if(Material
&& Material
->Spoils())
1459 int item::GetMaxSpoilPercentage() const
1461 int MaxPercentage
= 0;
1463 for(int c
= 0; c
< GetMaterials(); ++c
)
1465 cmaterial
* Material
= GetMaterial(c
);
1468 MaxPercentage
= Max(MaxPercentage
, Material
->GetSpoilPercentage());
1471 return MaxPercentage
;
1474 truth
item::HasPrice() const
1476 return GetPrice() || GetMaterialPrice();
1479 void item::Disappear()
1485 outputfile
& operator<<(outputfile
& SaveFile
, const idholder
* IdHolder
)
1487 SaveFile
<< IdHolder
->ID
;
1491 inputfile
& operator>>(inputfile
& SaveFile
, idholder
*& IdHolder
)
1493 IdHolder
= new idholder(ReadType
<feuLong
>(SaveFile
));
1497 festring
item::GetExtendedDescription() const
1499 if(!CanBeSeenByPlayer())
1500 return CONST_S("something");
1503 ccharacter
* Carrier
= FindCarrier();
1507 if(Carrier
->IsPlayer())
1510 AddName(Desc
, UNARTICLED
);
1513 else if(Carrier
->CanBeSeenByPlayer())
1515 Carrier
->AddName(Desc
, DEFINITE
);
1517 AddName(Desc
, UNARTICLED
);
1522 AddName(Desc
, DEFINITE
);
1525 GetLSquareUnder()->AddLocationDescription(Desc
);
1530 ccharacter
* item::FindCarrier() const
1532 return Slot
[0]->FindCarrier();
1535 /* returns 0 if not worn or wielded else the wearer */
1537 const character
* item::GetWearer() const
1539 if(!GetSlot()->IsGearSlot())
1542 return FindCarrier();
1545 void itemlock::PostConstruct()
1547 /* Terrible gum solution! */
1549 if(!(GetVirtualConfig() & LOCK_BITS
))
1551 int NormalLockTypes
= 0;
1552 const itemdatabase
*const* ConfigData
= GetVirtualProtoType()->GetConfigData();
1553 int c
, ConfigSize
= GetVirtualProtoType()->GetConfigSize();
1555 for(c
= 0; c
< ConfigSize
; ++c
)
1556 if(ConfigData
[c
]->Config
& LOCK_BITS
1557 && (ConfigData
[c
]->Config
& ~LOCK_BITS
) == GetVirtualConfig()
1558 && !(ConfigData
[c
]->Config
& S_LOCK_ID
))
1561 int ChosenLock
= RAND() % NormalLockTypes
;
1563 for(c
= 0; c
< ConfigSize
; ++c
)
1564 if(ConfigData
[c
]->Config
& LOCK_BITS
1565 && (ConfigData
[c
]->Config
& ~LOCK_BITS
) == GetVirtualConfig()
1566 && !(ConfigData
[c
]->Config
& S_LOCK_ID
)
1569 SetVirtualConfig(ConfigData
[c
]->Config
, NO_PIC_UPDATE
);
1575 truth
itemlock::TryKey(item
* Key
, character
* Applier
)
1577 if(GetVirtualConfig() & BROKEN_LOCK
)
1579 ADD_MESSAGE("The lock is broken.");
1583 if(Key
->CanOpenLockType(GetVirtualConfig()&LOCK_BITS
))
1587 if(Applier
->IsPlayer())
1588 ADD_MESSAGE("You unlock %s.", GetVirtualDescription(DEFINITE
).CStr());
1589 else if(Applier
->CanBeSeenByPlayer())
1590 ADD_MESSAGE("%s unlocks %s.", Applier
->CHAR_NAME(DEFINITE
), GetVirtualDescription(DEFINITE
).CStr());
1594 if(Applier
->IsPlayer())
1595 ADD_MESSAGE("You lock %s.", GetVirtualDescription(DEFINITE
).CStr());
1596 else if(Applier
->CanBeSeenByPlayer())
1597 ADD_MESSAGE("%s locks %s.", Applier
->CHAR_NAME(DEFINITE
), GetVirtualDescription(DEFINITE
).CStr());
1604 if(Applier
->IsPlayer())
1605 ADD_MESSAGE("%s doesn't fit in the lock.", Key
->CHAR_NAME(DEFINITE
));
1606 else if(Applier
->CanBeSeenByPlayer())
1607 ADD_MESSAGE("%s tries to fit %s in the lock, but fails.", Applier
->CHAR_NAME(DEFINITE
), Key
->CHAR_NAME(DEFINITE
));
1613 void itemlock::Save(outputfile
& SaveFile
) const
1618 void itemlock::Load(inputfile
& SaveFile
)
1623 truth
item::IsBeverage(ccharacter
*) const
1625 for(int c
= 0; c
< GetMaterials(); ++c
)
1627 cmaterial
* Material
= GetMaterial(c
);
1629 if(Material
&& (Material
->GetCategoryFlags() & IS_BEVERAGE
))
1640 SendMemorizedUpdateRequest();
1646 ItemFlags
&= ~HASTE
;
1647 SendMemorizedUpdateRequest();
1650 void item::SendMemorizedUpdateRequest() const
1652 if(!game::IsInWilderness())
1653 for(int c
= 0; c
< SquaresUnder
; ++c
)
1656 lsquare
* Square
= GetLSquareUnder(c
);
1657 Square
->SendMemorizedUpdateRequest();
1661 truth
item::AddStateDescription(festring
& Name
, truth Articled
) const
1666 if((ItemFlags
& (HASTE
|SLOW
)) && Articled
)
1669 if(ItemFlags
& HASTE
)
1672 if(ItemFlags
& SLOW
)
1679 truth
item::Burn (character
*who
, v2 where
, int dir
) {
1680 //who->EditExperience(PERCEPTION, 150, 1 << 10);
1681 where
+= game::GetMoveVector(dir
);
1682 area
*ca
= who
->GetSquareUnder()->GetArea();
1683 if (where
.X
< 0 || where
.Y
< 0 || where
.X
>= ca
->GetXSize() || where
.Y
>= ca
->GetYSize()) return false;
1684 lsquare
*sq
= static_cast<lsquare
*>(ca
->GetSquare(where
.X
, where
.Y
));
1686 sq
->ReceiveTrapDamage(who
, 50, FIRE
, dir
);