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
); }
61 truth
item::IsOnGround () const { return Slot
[0]->IsOnGround(); }
62 truth
item::IsSimiliarTo (item
*Item
) const { return Item
->GetType() == GetType() && Item
->GetConfig() == GetConfig(); }
63 double item::GetBaseDamage () const { return Max(0.0, sqrt(5e-5*GetWeaponStrength())+GetDamageBonus()); }
64 int item::GetBaseMinDamage () const { return int(GetBaseDamage()*0.75); }
65 int item::GetBaseMaxDamage () const { return int(GetBaseDamage()*1.25)+1; }
66 int item::GetBaseToHitValue () const { return int(10000.0/(1000+GetWeight())+GetTHVBonus()); }
67 int item::GetBaseBlockValue () const { return int((10000.0/(1000+GetWeight())+GetTHVBonus())*GetBlockModifier()/10000.0); }
68 truth
item::IsInCorrectSlot (int I
) const { return I
== RIGHT_WIELDED_INDEX
|| I
== LEFT_WIELDED_INDEX
; }
69 truth
item::IsInCorrectSlot () const { return IsInCorrectSlot(static_cast<gearslot
*>(*Slot
)->GetEquipmentIndex()); }
70 int item::GetEquipmentIndex () const { return static_cast<gearslot
*>(*Slot
)->GetEquipmentIndex(); }
71 int item::GetGraphicsContainerIndex () const { return GR_ITEM
; }
72 truth
item::IsBroken () const { return GetConfig () & BROKEN
; }
73 truth
item::IsFood() const { return DataBase
->Category
& FOOD
; }
74 cchar
*item::GetBreakVerb () const { return "breaks"; }
75 square
*item::GetSquareUnderEntity (int I
) const { return GetSquareUnder(I
); }
76 square
*item::GetSquareUnder (int I
) const { return Slot
[I
] ? Slot
[I
]->GetSquareUnder () : 0; }
77 lsquare
*item::GetLSquareUnder (int I
) const { return static_cast<lsquare
*>(Slot
[I
]->GetSquareUnder ()); }
78 void item::SignalStackAdd (stackslot
*StackSlot
, void (stack::*)(item
*, truth
)) { Slot
[0] = StackSlot
; }
79 truth
item::IsAnimated () const { return GraphicData
.AnimationFrames
> 1 || (Fluid
&& ShowFluids ()); }
80 truth
item::IsRusted () const { return MainMaterial
->GetRustLevel () != NOT_RUSTED
; }
81 truth
item::IsEatable (ccharacter
*Eater
) const { return GetConsumeMaterial(Eater
, &material::IsSolid
) && IsConsumable (); }
82 truth
item::IsDrinkable (ccharacter
*Eater
) const { return GetConsumeMaterial(Eater
, &material::IsLiquid
) && IsConsumable (); }
83 pixelpredicate
item::GetFluidPixelAllowedPredicate () const { return &rawbitmap::IsTransparent
; }
84 void item::Cannibalize () { Flags
|= CANNIBALIZED
; }
85 void item::SetMainMaterial (material
*NewMaterial
, int SpecialFlags
) { SetMaterial(MainMaterial
, NewMaterial
, GetDefaultMainVolume (), SpecialFlags
); }
86 void item::ChangeMainMaterial (material
*NewMaterial
, int SpecialFlags
) { ChangeMaterial(MainMaterial
, NewMaterial
, GetDefaultMainVolume (), SpecialFlags
); }
87 void item::InitMaterials (const materialscript
*M
, const materialscript
*, truth CUP
) { InitMaterials(M
->Instantiate (), CUP
); }
88 int item::GetMainMaterialRustLevel () const { return MainMaterial
->GetRustLevel(); }
91 item::item (citem
&Item
) :
95 DataBase(Item
.DataBase
),
100 SquaresUnder(Item
.SquaresUnder
),
101 LifeExpectancy(Item
.LifeExpectancy
),
102 ItemFlags(Item
.ItemFlags
)
104 Flags
&= ENTITY_FLAGS
|SQUARE_POSITION_BITS
;
105 ID
= game::CreateNewItemID(this);
106 CloneMotherID
= new idholder(Item
.ID
);
107 idholder
* TI
= CloneMotherID
;
109 for (idholder
* II
= Item
.CloneMotherID
; II
; II
= II
->Next
) TI
= TI
->Next
= new idholder(II
->ID
);
111 Slot
= new slot
*[SquaresUnder
];
112 for (int c
= 0; c
< SquaresUnder
; ++c
) Slot
[c
] = 0;
118 game::RemoveItemID(ID
);
121 for (int c
= 0; c
< /*SquaresUnder*/FluidCount
; ++c
) deleteList(FP
[c
]);
124 deleteList(CloneMotherID
);
128 void item::Fly (character
*Thrower
, int Direction
, int Force
) {
129 int Range
= Force
*25/Max(sLong(sqrt(GetWeight())), 1);
130 lsquare
*LSquareUnder
= GetLSquareUnder();
132 LSquareUnder
->GetStack()->AddItem(this, false);
133 if (!Range
|| GetSquaresUnder() != 1) {
134 if (GetLSquareUnder()->GetRoom()) GetLSquareUnder()->GetRoom()->AddItemEffect(this);
137 if (Direction
== RANDOM_DIR
) Direction
= RAND()&7;
138 v2 StartingPos
= GetPos();
139 v2 Pos
= StartingPos
;
140 v2 DirVector
= game::GetMoveVector(Direction
);
141 truth Breaks
= false;
142 double BaseDamage
, BaseToHitValue
;
145 int Bonus
= Thrower
->IsHumanoid() ? Thrower
->GetCWeaponSkill(GetWeaponCategory())->GetBonus() : 1000;
146 BaseDamage
= sqrt(5e-12 * GetWeaponStrength() * Force
/ Range
) * Bonus
;
147 BaseToHitValue
= 10 * Bonus
* Thrower
->GetMoveEase() / (500 + GetWeight()) * Thrower
->GetAttribute(DEXTERITY
) * sqrt(2.5e-8 * Thrower
->GetAttribute(PERCEPTION
)) / Range
;
149 BaseDamage
= sqrt(5e-6 * GetWeaponStrength() * Force
/ Range
);
150 BaseToHitValue
= 10 * 100 / (500 + GetWeight()) / Range
;
153 for (RangeLeft
= Range
; RangeLeft
; --RangeLeft
) {
154 if (!GetLevel()->IsValidPos(Pos
+DirVector
)) break;
155 lsquare
*JustHit
= GetNearLSquare(Pos
+DirVector
);
156 if (!JustHit
->IsFlyable()) {
158 JustHit
->GetOLTerrain()->HasBeenHitByItem(Thrower
, this, int(BaseDamage
*sqrt(RangeLeft
)));
161 clock_t StartTime
= clock();
164 JustHit
->GetStack()->AddItem(this, false);
165 truth Draw
= game::OnScreen(JustHit
->GetPos()) && JustHit
->CanBeSeenByPlayer();
166 if (Draw
) game::DrawEverything();
167 if (JustHit
->GetCharacter()) {
168 int Damage
= int(BaseDamage
* sqrt(RangeLeft
));
169 double ToHitValue
= BaseToHitValue
*RangeLeft
;
170 int Returned
= HitCharacter(Thrower
, JustHit
->GetCharacter(), Damage
, ToHitValue
, Direction
);
171 if (Returned
== HIT
) Breaks
= true;
172 if (Returned
!= MISSED
) break;
174 if (Draw
) { while (clock()-StartTime
< 0.03 * CLOCKS_PER_SEC
); } //FIXME
177 if (Breaks
) ReceiveDamage(Thrower
, int(sqrt(GetWeight()*RangeLeft
) / 10), THROW
|PHYSICAL_DAMAGE
, Direction
);
178 if (Exists() && GetLSquareUnder()->GetRoom()) GetLSquareUnder()->GetRoom()->AddItemEffect(this);
182 int item::HitCharacter (character
*Thrower
, character
*Dude
, int Damage
, double ToHitValue
, int Direction
) {
183 if (Dude
->Catches(this)) return CATCHED
;
184 if (Thrower
&& !EffectIsGood()) Thrower
->Hostility(Dude
);
185 if (Dude
->DodgesFlyingItem(this, ToHitValue
)) {
186 if (Dude
->IsPlayer()) ADD_MESSAGE("%s misses you.", CHAR_NAME(DEFINITE
));
187 else if (Dude
->CanBeSeenByPlayer()) ADD_MESSAGE("%s misses %s.", CHAR_NAME(DEFINITE
), Dude
->CHAR_NAME(DEFINITE
));
190 Dude
->HasBeenHitByItem(Thrower
, this, Damage
, ToHitValue
, Direction
);
195 double item::GetWeaponStrength () const {
196 return GetFormModifier() * GetMainMaterial()->GetStrengthValue() * sqrt(GetMainMaterial()->GetWeight());
200 int item::GetStrengthRequirement () const {
201 double WeightTimesSize
= GetWeight() * GetSize();
202 return int(1.25e-10 * WeightTimesSize
* WeightTimesSize
);
206 truth
item::Apply (character
*Applier
) {
207 if (Applier
->IsPlayer()) ADD_MESSAGE("You can't apply this!");
212 /* Returns truth that tells whether the Polymorph really happened */
213 truth
item::Polymorph (character
*Polymorpher
, stack
*CurrentStack
) {
214 if (!IsPolymorphable()) return false;
215 if (Polymorpher
&& IsOnGround()) {
216 room
*Room
= GetRoom();
217 if (Room
) Room
->HostileAction(Polymorpher
);
219 if (GetSquarePosition() != CENTER
) {
220 stack
*Stack
= CurrentStack
->GetLSquareUnder()->GetStackOfAdjacentSquare(GetSquarePosition());
221 if (Stack
) CurrentStack
= Stack
;
223 CurrentStack
->AddItem(protosystem::BalancedCreateItem(0, 0, MAX_PRICE
, ANY_CATEGORY
, 0, 0, 0, true));
230 /* Returns whether the Eater must stop eating the item */
231 truth
item::Consume (character
*Eater
, sLong Amount
) {
232 material
*ConsumeMaterial
= GetConsumeMaterial(Eater
);
233 if (!ConsumeMaterial
) return true;
234 if (Eater
->IsPlayer() && !(Flags
& CANNIBALIZED
) && Eater
->CheckCannibalism(ConsumeMaterial
)) {
235 game::DoEvilDeed(25);
236 ADD_MESSAGE("You feel that this was an evil deed.");
239 feuLong ID
= GetID();
240 material
*Garbage
= ConsumeMaterial
->EatEffect(Eater
, Amount
);
241 item
*NewConsuming
= GetID() ? this : game::SearchItem(ID
);
242 material
*NewConsumeMaterial
= NewConsuming
->GetConsumeMaterial(Eater
);
243 if (!NewConsuming
->Exists() || !NewConsumeMaterial
|| !NewConsumeMaterial
->IsSameAs(ConsumeMaterial
))
244 ConsumeMaterial
->FinishConsuming(Eater
);
246 return !NewConsuming
->Exists() || !NewConsumeMaterial
;
250 truth
item::CanBeEatenByAI (ccharacter
*Eater
) const {
251 material
*ConsumeMaterial
= GetConsumeMaterial(Eater
);
252 return (!Eater
->IsPet()
253 || !(Eater
->GetCommandFlags() & DONT_CONSUME_ANYTHING_VALUABLE
)
256 && ConsumeMaterial
&& ConsumeMaterial
->CanBeEatenByAI(Eater
);
260 void item::Save (outputfile
&SaveFile
) const {
261 SaveFile
<< (uShort
)GetType();
262 object::Save(SaveFile
);
263 SaveFile
<< (uShort
)0;
264 SaveFile
<< mIsStepedOn
;
265 SaveFile
<< (uShort
)GetConfig();
266 SaveFile
<< (uShort
)Flags
;
267 SaveFile
<< Size
<< ID
<< LifeExpectancy
<< ItemFlags
;
268 SaveFile
<< pickupTime
;
269 SaveLinkedList(SaveFile
, CloneMotherID
);
272 SaveFile
<< FluidCount
;
273 for (int c
= 0; c
< /*SquaresUnder*/FluidCount
; ++c
) SaveLinkedList(SaveFile
, Fluid
[c
]);
280 void item::Load (inputfile
&SaveFile
) {
281 object::Load(SaveFile
);
282 int ver
= ReadType(uShort
, SaveFile
);
283 if (ver
!= 0) ABORT("invalid item version in savefile: %d", ver
);
284 SaveFile
>> mIsStepedOn
;
285 databasecreator
<item
>::InstallDataBase(this, ReadType(uShort
, SaveFile
));
286 Flags
|= ReadType(uShort
, SaveFile
) & ~ENTITY_FLAGS
;
287 SaveFile
>> Size
>> ID
>> LifeExpectancy
>> ItemFlags
;
288 SaveFile
>> pickupTime
;
289 LoadLinkedList(SaveFile
, CloneMotherID
);
290 if (LifeExpectancy
) Enable();
291 game::AddItemID(this, ID
);
292 if (SaveFile
.Get()) {
293 SaveFile
>> FluidCount
;
294 Fluid
= new fluid
*[/*SquaresUnder*/FluidCount
];
295 for (int c
= 0; c
< /*SquaresUnder*/FluidCount
; ++c
) {
296 LoadLinkedList(SaveFile
, Fluid
[c
]);
297 for (fluid
*F
= Fluid
[c
]; F
; F
= F
->Next
) F
->SetMotherItem(this);
300 if (Fluid
) Fluid
= 0; //FIXME: MEMORY LEAK
304 const fearray<festring> < = GetLevelTags();
306 fprintf(stderr, "====\n");
307 for (uInt f = 0; f < lt.Size; ++f) fprintf(stderr, " %u: [%s]\n", f, lt[f].CStr());
313 void item::TeleportRandomly () {
314 if (GetSquaresUnder() == 1) {
316 lsquare
*Square
= GetNearLSquare(GetLevel()->GetRandomSquare());
317 MoveTo(Square
->GetStack());
318 if (Square
->CanBeSeenByPlayer()) ADD_MESSAGE("Suddenly %s appears!", CHAR_NAME(INDEFINITE
));
323 int item::GetStrengthValue () const {
324 return sLong(GetStrengthModifier()) * GetMainMaterial()->GetStrengthValue() / 2000;
328 void item::RemoveFromSlot () {
329 for (int c
= 0; c
< SquaresUnder
; ++c
) {
333 } catch (quitrequest
) {
343 void item::MoveTo (stack
*Stack
, truth setPickupTime
) {
345 Stack
->AddItem(this);
347 pickupTime
= game::GetTick();
348 //fprintf(stderr, "item '%s'; pickuptime set to %u\n", GetNameSingular().CStr(), pickupTime);
353 cchar
*item::GetItemCategoryName (sLong Category
) {
355 if (Category
== HELMET
) return "Helmets";
356 if (Category
== AMULET
) return "Amulets";
357 if (Category
== CLOAK
) return "Cloaks";
358 if (Category
== BODY_ARMOR
) return "Body armors";
359 if (Category
== WEAPON
) return "Weapons";
360 if (Category
== SHIELD
) return "Shields";
361 if (Category
== RING
) return "Rings";
362 if (Category
== GAUNTLET
) return "Gauntlets";
363 if (Category
== BELT
) return "Belts";
364 if (Category
== BOOT
) return "Boots";
365 if (Category
== FOOD
) return "Food";
366 if (Category
== POTION
) return "Potions";
367 if (Category
== SCROLL
) return "Scrolls";
368 if (Category
== BOOK
) return "Books";
369 if (Category
== WAND
) return "Wands";
370 if (Category
== TOOL
) return "Tools";
371 if (Category
== VALUABLE
) return "Valuables";
372 if (Category
== MISC
) return "Miscellaneous items";
377 int item::GetResistance (int Type
) const {
378 if ((Type
&0xFFF) == PHYSICAL_DAMAGE
) return GetStrengthValue();
379 if ((Type
&0xFFF) == ENERGY
) return GetEnergyResistance();
380 if ((Type
&0xFFF) == DRAIN
|| (Type
&0xFFF) == MUSTARD_GAS_DAMAGE
) return 0;
381 if ((Type
&0xFFF) == FIRE
) return GetFireResistance();
382 if ((Type
&0xFFF) == POISON
) return GetPoisonResistance();
383 if ((Type
&0xFFF) == ELECTRICITY
) return GetElectricityResistance();
384 if ((Type
&0xFFF) == ACID
) return GetAcidResistance();
385 if ((Type
&0xFFF) == SOUND
) return GetSoundResistance();
386 ABORT("Resistance lack detected!");
391 truth
item::Open (character
*Char
) {
392 if (Char
->IsPlayer()) ADD_MESSAGE("You can't open %s.", CHAR_NAME(DEFINITE
));
397 item
*itemprototype::SpawnAndLoad (inputfile
&SaveFile
) const {
398 item
*Item
= Spawner(0, LOAD
);
399 Item
->Load(SaveFile
);
400 Item
->CalculateAll();
405 void item::LoadDataBaseStats () {
406 SetSize(GetDefaultSize());
410 void item::Initialize (int NewConfig
, int SpecialFlags
) {
411 CalculateSquaresUnder();
412 Slot
= new slot
*[SquaresUnder
];
413 for (int c
= 0; c
< SquaresUnder
; ++c
) Slot
[c
] = 0;
414 if (!(SpecialFlags
& LOAD
)) {
415 ID
= game::CreateNewItemID(this);
416 databasecreator
<item
>::InstallDataBase(this, NewConfig
);
418 RandomizeVisualEffects();
419 Flags
|= CENTER
<< SQUARE_POSITION_SHIFT
;
420 if (!(SpecialFlags
& NO_MATERIALS
)) GenerateMaterials();
422 if (!(SpecialFlags
& LOAD
)) PostConstruct();
423 if (!(SpecialFlags
& (LOAD
|NO_MATERIALS
))) {
425 if (!(SpecialFlags
& NO_PIC_UPDATE
)) UpdatePictures();
430 truth
item::ShowMaterial () const {
431 if (GetMainMaterialConfig().Size
== 1) return GetMainMaterial()->GetConfig() != GetMainMaterialConfig()[0];
432 //FIXME: gum solution
433 if (GetNameSingular() == "bone") {
434 // never show the material for 'bone bone'
435 if (GetMainMaterial()->GetConfig() == BONE
) return false;
441 sLong
item::GetBlockModifier() const
444 return GetSize() * GetRoundness() << 1;
446 return GetSize() * GetRoundness() << 2;
449 truth
item::CanBeSeenByPlayer() const
451 return CanBeSeenBy(PLAYER
);
454 truth
item::CanBeSeenBy(ccharacter
* Who
) const
456 for(int c
= 0; c
< SquaresUnder
; ++c
)
457 if(Slot
[c
] && Slot
[c
]->CanBeSeenBy(Who
))
460 return Who
->IsPlayer() && game::GetSeeWholeMapCheatMode();
463 festring
item::GetDescription(int Case
) const
465 if(CanBeSeenByPlayer())
466 return GetName(Case
);
468 return CONST_S("something");
471 void item::SignalVolumeAndWeightChange()
473 CalculateVolumeAndWeight();
475 for(int c
= 0; c
< SquaresUnder
; ++c
)
477 Slot
[c
]->SignalVolumeAndWeightChange();
480 void item::CalculateVolumeAndWeight()
484 for(int c
= 0; c
< GetMaterials(); ++c
)
486 cmaterial
* Material
= GetMaterial(c
);
490 Volume
+= Material
->GetVolume();
491 Weight
+= Material
->GetWeight();
496 void item::SignalEmitationIncrease(col24 EmitationUpdate
)
498 if(game::CompareLights(EmitationUpdate
, Emitation
) > 0)
500 game::CombineLights(Emitation
, EmitationUpdate
);
502 for(int c
= 0; c
< SquaresUnder
; ++c
)
504 Slot
[c
]->SignalEmitationIncrease(EmitationUpdate
);
508 void item::SignalEmitationDecrease(col24 EmitationUpdate
)
510 if(game::CompareLights(EmitationUpdate
, Emitation
) >= 0 && Emitation
)
512 col24 Backup
= Emitation
;
513 CalculateEmitation();
515 if(Backup
!= Emitation
)
516 for(int c
= 0; c
< SquaresUnder
; ++c
)
518 Slot
[c
]->SignalEmitationDecrease(EmitationUpdate
);
522 void item::CalculateAll()
524 CalculateVolumeAndWeight();
525 CalculateEmitation();
528 /* Temporary and buggy. */
530 void item::WeaponSkillHit(int Hits
)
532 if(Slot
[0] && Slot
[0]->IsGearSlot())
533 static_cast<arm
*>(static_cast<gearslot
*>(*Slot
)->GetBodyPart())->WieldedSkillHit(Hits
);
536 /* Returns 0 if item cannot be cloned */
538 item
* item::Duplicate(feuLong Flags
)
540 if(!(Flags
& IGNORE_PROHIBITIONS
)
541 && ((!(Flags
& MIRROR_IMAGE
) && !CanBeCloned())
542 || (Flags
& MIRROR_IMAGE
&& (!CanBeMirrored()
544 && !(MainMaterial
->GetCommonFlags() & CAN_BE_MIRRORED
))
545 || (GetSecondaryMaterial()
546 && !(GetSecondaryMaterial()->GetCommonFlags() & CAN_BE_MIRRORED
))))))
549 item
* Clone
= GetProtoType()->Clone(this);
551 if(Flags
& MIRROR_IMAGE
)
552 Clone
->SetLifeExpectancy(Flags
>> LE_BASE_SHIFT
& LE_BASE_RANGE
,
553 Flags
>> LE_RAND_SHIFT
& LE_RAND_RANGE
);
555 idholder
* I
= new idholder(ID
);
556 I
->Next
= CloneMotherID
;
558 game::RemoveItemID(ID
);
559 ID
= game::CreateNewItemID(this);
560 Clone
->UpdatePictures();
564 void item::AddInventoryEntry(ccharacter
*, festring
& Entry
, int Amount
, truth ShowSpecialInfo
) const
567 AddName(Entry
, INDEFINITE
);
570 Entry
<< Amount
<< ' ';
571 AddName(Entry
, PLURAL
);
575 Entry
<< " [\1C" << GetWeight() * Amount
<< "g\2]";
578 const itemdatabase
* itemprototype::ChooseBaseForConfig(itemdatabase
** TempConfig
, int Configs
, int ConfigNumber
)
580 if(!(ConfigNumber
& BROKEN
))
584 ConfigNumber
^= BROKEN
;
586 for(int c
= 0; c
< Configs
; ++c
)
587 if(TempConfig
[c
]->Config
== ConfigNumber
)
588 return TempConfig
[c
];
594 truth
item::ReceiveDamage(character
* Damager
, int Damage
, int Type
, int Dir
)
596 if(CanBeBroken() && !IsBroken() && Type
& (PHYSICAL_DAMAGE
|SOUND
|ENERGY
|ACID
))
598 int StrengthValue
= GetStrengthValue();
603 if(Damage
> StrengthValue
<< 2 && RAND() & 3 && RAND() % (25 * Damage
/ StrengthValue
) >= 100)
610 if(Type
& ACID
&& IsBroken() && IsDestroyable(Damager
))
612 int StrengthValue
= GetStrengthValue();
617 if(Damage
> StrengthValue
<< 4 && !(RAND() & 3) && RAND() % (100 * Damage
/ StrengthValue
) >= 100)
619 Destroy(Damager
, Dir
);
627 void itemdatabase::InitDefaults (const itemprototype
*NewProtoType
, int NewConfig
, cfestring
&acfgstrname
)
630 ProtoType
= NewProtoType
;
632 CfgStrName
= acfgstrname
;
634 if(NewConfig
& BROKEN
)
636 if(Adjective
.GetSize())
637 Adjective
.Insert(0, "broken ");
639 Adjective
= CONST_S("broken");
643 StrengthModifier
>>= 1;
647 sLong
item::GetNutritionValue() const
651 for(int c
= 0; c
< GetMaterials(); ++c
)
653 NV
+= GetMaterial(c
)->GetTotalNutritionValue();
658 void item::SignalSpoil(material
*)
663 if(CanBeSeenByPlayer())
664 ADD_MESSAGE("%s spoils completely.", GetExtendedDescription().CStr());
666 truth Equipped
= PLAYER
->Equips(this);
670 game::AskForEscPress(CONST_S("Equipment destroyed!"));
673 item
* item::DuplicateToStack(stack
* CurrentStack
, feuLong Flags
)
675 item
* Duplicated
= Duplicate(Flags
);
680 CurrentStack
->AddItem(Duplicated
);
684 truth
item::CanBePiledWith(citem
* Item
, ccharacter
* Viewer
) const
686 return (GetType() == Item
->GetType()
687 && GetConfig() == Item
->GetConfig()
688 && ItemFlags
== Item
->ItemFlags
689 && (WeightIsIrrelevant() || Weight
== Item
->Weight
)
690 && MainMaterial
->IsSameAs(Item
->MainMaterial
)
691 && MainMaterial
->GetSpoilLevel() == Item
->MainMaterial
->GetSpoilLevel()
692 && MainMaterial
->GetRustLevel() == Item
->MainMaterial
->GetRustLevel()
693 && Viewer
->GetCWeaponSkillLevel(this) == Viewer
->GetCWeaponSkillLevel(Item
)
694 && Viewer
->GetSWeaponSkillLevel(this) == Viewer
->GetSWeaponSkillLevel(Item
)
695 && !Fluid
&& !Item
->Fluid
696 && !LifeExpectancy
== !Item
->LifeExpectancy
);
699 void item::Break(character
* Breaker
, int)
701 if(CanBeSeenByPlayer())
702 ADD_MESSAGE("%s %s.", GetExtendedDescription().CStr(), GetBreakVerb());
704 if(Breaker
&& IsOnGround())
706 room
* Room
= GetRoom();
709 Room
->HostileAction(Breaker
);
712 item
* Broken
= GetProtoType()->Clone(this);
713 Broken
->SetConfig(GetConfig() | BROKEN
);
714 Broken
->SetSize(Broken
->GetSize() >> 1);
715 DonateFluidsTo(Broken
);
717 DonateSlotTo(Broken
);
720 if(PLAYER
->Equips(Broken
))
721 game::AskForEscPress(CONST_S("Equipment broken!"));
726 MainMaterial
->Be(ItemFlags
);
728 if (Exists() && LifeExpectancy
) {
729 if (LifeExpectancy
== 1) {
730 if (CanBeSeenByPlayer()) ADD_MESSAGE("%s disappears.", GetExtendedDescription().CStr());
731 truth Equipped
= PLAYER
->Equips(this);
733 if (Equipped
) game::AskForEscPress(CONST_S("Equipment destroyed!"));
740 int item::GetOfferValue(int Receiver
) const
744 int OfferValue
= int(sqrt(GetTruePrice()));
746 if(Receiver
== GetAttachedGod())
754 void item::SignalEnchantmentChange()
756 for(int c
= 0; c
< SquaresUnder
; ++c
)
758 Slot
[c
]->SignalEnchantmentChange();
761 sLong
item::GetEnchantedPrice(int Enchantment
) const
763 return !PriceIsProportionalToEnchantment() ? item::GetPrice() : Max
<int>(item::GetPrice() * Enchantment
* Enchantment
, 0);
772 Fixed
= GetProtoType()->Clone(this);
773 Fixed
->SetConfig(GetConfig() ^ BROKEN
);
774 Fixed
->SetSize(Fixed
->GetSize() << 1);
775 DonateFluidsTo(Fixed
);
784 void item::DonateSlotTo(item
* Item
)
788 Slot
[0]->DonateTo(Item
);
791 for(int c
= 1; c
< SquaresUnder
; ++c
)
800 int item::GetSpoilLevel() const
802 return MainMaterial
->GetSpoilLevel();
805 void item::SignalSpoilLevelChange(material
*)
807 if(!IsAnimated() && GetSpoilLevel() && Slot
[0] && Slot
[0]->IsVisible())
808 for(int c
= 0; c
< SquaresUnder
; ++c
)
809 GetSquareUnder(c
)->IncStaticAnimatedEntities();
811 SignalVolumeAndWeightChange(); // gum
815 truth
item::AllowSpoil() const
819 lsquare
* Square
= GetLSquareUnder();
820 int RoomNumber
= Square
->GetRoomIndex();
821 return !RoomNumber
|| Square
->GetLevel()->GetRoom(RoomNumber
)->AllowSpoil(this);
827 void item::ResetSpoiling()
829 for(int c
= 0; c
< GetMaterials(); ++c
)
831 GetMaterial(c
)->ResetSpoiling();
834 cchar
* item::GetBaseToHitValueDescription() const
836 if(GetBaseToHitValue() < 10)
837 return ToHitValueDescription
[Min(GetBaseToHitValue(), 6)];
839 return ToHitValueDescription
[7];
842 cchar
* item::GetBaseBlockValueDescription() const
844 if(GetBaseBlockValue() < 20)
845 return ToHitValueDescription
[Min(GetBaseBlockValue() >> 1, 6)];
847 return ToHitValueDescription
[7];
850 cchar
* item::GetStrengthValueDescription() const
852 int SV
= GetStrengthValue();
855 return StrengthValueDescription
[0];
857 return StrengthValueDescription
[1];
859 return StrengthValueDescription
[2];
861 return StrengthValueDescription
[3];
863 return StrengthValueDescription
[4];
865 return StrengthValueDescription
[5];
867 return StrengthValueDescription
[6];
870 void item::SpecialGenerationHandler()
873 Slot
[0]->AddFriendItem(Duplicate());
876 void item::SortAllItems(const sortdata
& SortData
) const
878 if(SortData
.Sorter
== 0 || (this->*SortData
.Sorter
)(SortData
.Character
))
879 SortData
.AllItems
.push_back(const_cast<item
*>(this));
882 int item::GetAttachedGod() const
884 return DataBase
->AttachedGod
? DataBase
->AttachedGod
: MainMaterial
->GetAttachedGod();
887 sLong
item::GetMaterialPrice() const
889 return MainMaterial
->GetRawPrice();
892 sLong
item::GetTruePrice() const
897 sLong Price
= Max(GetPrice(), GetMaterialPrice());
900 Price
= Price
* (100 - GetMaxSpoilPercentage()) / 500;
907 void item::AddAttackInfo(felist
& List
) const
909 festring
Entry(40, ' ');
910 Entry
<< int(GetWeight());
912 Entry
<< int(GetSize());
914 Entry
<< int(GetStrengthRequirement());
916 Entry
<< GetBaseMinDamage() << '-' << GetBaseMaxDamage();
917 List
.AddEntry(Entry
, LIGHT_GRAY
);
920 void item::AddMiscellaneousInfo(felist
& List
) const
922 festring
Entry(40, ' ');
923 Entry
<< int(GetTruePrice());
925 Entry
<< GetOfferValue(0);
927 Entry
<< int(GetNutritionValue());
928 List
.AddEntry(Entry
, LIGHT_GRAY
);
934 void item::PreProcessForBone () {
939 game::RemoveItemID(ID
);
941 game::AddItemID(this, ID
);
947 void item::PostProcessForBone () {
948 boneidmap::iterator BI
= game::GetBoneItemIDMap().find(-ID
);
949 game::RemoveItemID(ID
);
951 if (BI
== game::GetBoneItemIDMap().end()) {
952 feuLong NewID
= game::CreateNewItemID(this);
953 game::GetBoneItemIDMap().insert(std::make_pair(-ID
, NewID
));
956 if (game::SearchItem(BI
->second
)) {
958 game::AddItemID(this, ID
);
961 for (idholder
* I
= CloneMotherID
; I
; I
= I
->Next
) {
962 BI
= game::GetBoneItemIDMap().find(I
->ID
);
963 if (BI
== game::GetBoneItemIDMap().end()) {
964 feuLong NewCloneMotherID
= game::CreateNewItemID(0);
965 game::GetBoneItemIDMap().insert(std::make_pair(I
->ID
, NewCloneMotherID
));
966 I
->ID
= NewCloneMotherID
;
974 void item::SetConfig(int NewConfig
, int SpecialFlags
)
976 databasecreator
<item
>::InstallDataBase(this, NewConfig
);
979 if(!(SpecialFlags
& NO_PIC_UPDATE
))
983 god
* item::GetMasterGod() const
985 return game::GetGod(GetConfig());
989 int itemprototype::CreateSpecialConfigurations (itemdatabase
**TempConfig
, int Configs
, int Level
) {
990 if (Level
) return Configs
;
992 if (TempConfig
[0]->CreateDivineConfigurations
) {
993 Configs
= databasecreator
<item
>::CreateDivineConfigurations(this, TempConfig
, Configs
);
997 if (TempConfig
[0]->CreateLockConfigurations
) {
998 const item::database
*const* KeyConfigData
= key::ProtoType
.GetConfigData();
999 int KeyConfigSize
= key::ProtoType
.GetConfigSize();
1000 int OldConfigs
= Configs
;
1001 for (int c1
= 0; c1
< OldConfigs
; ++c1
) {
1002 if (!TempConfig
[c1
]->IsAbstract
) {
1003 int BaseConfig
= TempConfig
[c1
]->Config
;
1004 int NewConfig
= BaseConfig
| BROKEN_LOCK
;
1005 itemdatabase
* ConfigDataBase
= new itemdatabase(*TempConfig
[c1
]);
1007 lcfgname
<< TempConfig
[c1
]->CfgStrName
;
1008 lcfgname
<< "|locked-broken";
1010 ConfigDataBase
->InitDefaults(this, NewConfig
, lcfgname
);
1011 ConfigDataBase
->PostFix
<< "with a broken lock";
1012 ConfigDataBase
->Possibility
= 0;
1013 TempConfig
[Configs
++] = ConfigDataBase
;
1015 for (int c2
= 0; c2
< KeyConfigSize
; ++c2
) {
1017 xcfgname
<< TempConfig
[c1
]->CfgStrName
;
1018 xcfgname
<< "|locked";
1019 NewConfig
= BaseConfig
|KeyConfigData
[c2
]->Config
;
1020 ConfigDataBase
= new itemdatabase(*TempConfig
[c1
]);
1021 ConfigDataBase
->InitDefaults(this, NewConfig
, xcfgname
);
1022 ConfigDataBase
->PostFix
<< "with ";
1023 if (KeyConfigData
[c2
]->UsesLongAdjectiveArticle
) ConfigDataBase
->PostFix
<< "an "; else ConfigDataBase
->PostFix
<< "a ";
1024 ConfigDataBase
->PostFix
<< KeyConfigData
[c2
]->Adjective
<< " lock";
1025 ConfigDataBase
->Possibility
= 0;
1026 TempConfig
[Configs
++] = ConfigDataBase
;
1035 void item::Draw(blitdata
& BlitData
) const
1037 cint AF
= GraphicData
.AnimationFrames
;
1038 cint F
= !(BlitData
.CustomData
& ALLOW_ANIMATE
) || AF
== 1 ? 0 : GET_TICK() & (AF
- 1);
1039 cbitmap
* P
= GraphicData
.Picture
[F
];
1041 if(BlitData
.CustomData
& ALLOW_ALPHA
)
1042 P
->AlphaLuminanceBlit(BlitData
);
1044 P
->LuminanceMaskedBlit(BlitData
);
1046 if(Fluid
&& ShowFluids())
1047 DrawFluids(BlitData
);
1050 v2
item::GetLargeBitmapPos(v2 BasePos
, int I
) const
1052 cint SquareIndex
= I
? I
/ (GraphicData
.AnimationFrames
>> 2) : 0;
1053 return v2(SquareIndex
& 1 ? BasePos
.X
+ 16 : BasePos
.X
, SquareIndex
& 2 ? BasePos
.Y
+ 16 : BasePos
.Y
);
1056 void item::LargeDraw(blitdata
& BlitData
) const
1058 cint TrueAF
= GraphicData
.AnimationFrames
>> 2;
1059 cint SquareIndex
= BlitData
.CustomData
& SQUARE_INDEX_MASK
;
1060 cint F
= !(BlitData
.CustomData
& ALLOW_ANIMATE
) ? SquareIndex
* TrueAF
: SquareIndex
* TrueAF
+ (GET_TICK() & (TrueAF
- 1));
1061 cbitmap
* P
= GraphicData
.Picture
[F
];
1063 if(BlitData
.CustomData
& ALLOW_ALPHA
)
1064 P
->AlphaLuminanceBlit(BlitData
);
1066 P
->LuminanceMaskedBlit(BlitData
);
1069 void item::DonateIDTo(item
* Item
)
1071 game::RemoveItemID(Item
->ID
);
1072 game::UpdateItemID(Item
, ID
);
1077 void item::SignalRustLevelChange()
1079 SignalVolumeAndWeightChange();
1081 SendNewDrawAndMemorizedUpdateRequest();
1084 const rawbitmap
* item::GetRawPicture() const
1086 return igraph::GetRawGraphic(GetGraphicsContainerIndex());
1089 void item::RemoveFluid(fluid
*ToBeRemoved
) {
1090 truth WasAnimated
= IsAnimated();
1091 truth HasFluids
= false;
1093 if (Fluid
&& ToBeRemoved
) {
1094 for (int c
= 0; c
< /*SquaresUnder*/FluidCount
; ++c
) {
1095 fluid
*F
= Fluid
[c
];
1097 if (F
== ToBeRemoved
) {
1102 for (F
= F
->Next
; F
; LF
= F
, F
= F
->Next
) if (F
== ToBeRemoved
) { LF
->Next
= F
->Next
; break; }
1104 if (Fluid
[c
]) HasFluids
= true;
1108 if (!HasFluids
&& Fluid
) {
1111 if (!IsAnimated() != !WasAnimated
&& Slot
[0]->IsVisible()) GetSquareUnder()->DecStaticAnimatedEntities();
1113 if (ToBeRemoved
) SignalEmitationDecrease(ToBeRemoved
->GetEmitation());
1114 SignalVolumeAndWeightChange();
1118 void item::RemoveAllFluids () {
1120 for (int c
= 0; c
< /*SquaresUnder*/FluidCount
; ) {
1121 //fprintf(stderr, "c: %d; SquaresUnder: %d\n", c, SquaresUnder);
1122 fluid
*F
= Fluid
[c
];
1135 void item::AddFluid (liquid
*ToBeAdded
, festring LocationName
, int SquareIndex
, truth IsInside
) {
1136 truth WasAnimated
= IsAnimated();
1138 if (SquareIndex
< 0) ABORT("item::AddFluid(): invalid SquareIndex: %d", SquareIndex
);
1141 fluid
*F
= Fluid
[SquareIndex
];
1143 if (SquareIndex
>= FluidCount
) ABORT("item::AddFluid(): invalid SquareIndex: %d", SquareIndex
);
1145 Fluid
[SquareIndex
] = new fluid(ToBeAdded
, this, LocationName
, IsInside
);
1150 if (ToBeAdded
->IsSameAs(F
->GetLiquid())) {
1151 F
->AddLiquidAndVolume(ToBeAdded
->GetVolume());
1158 LF
->Next
= new fluid(ToBeAdded
, this, LocationName
, IsInside
);
1161 FluidCount
= SquaresUnder
;
1162 Fluid
= new fluid
*[/*SquaresUnder*/FluidCount
];
1163 if (SquareIndex
>= FluidCount
) ABORT("item::AddFluid(): invalid SquareIndex: %d", SquareIndex
);
1164 memset(Fluid
, 0, SquaresUnder
*sizeof(fluid
*));
1165 Fluid
[SquareIndex
] = new fluid(ToBeAdded
, this, LocationName
, IsInside
);
1169 SignalVolumeAndWeightChange();
1170 SignalEmitationIncrease(ToBeAdded
->GetEmitation());
1173 if (!IsAnimated() != !WasAnimated
&& Slot
[0]->IsVisible()) {
1174 GetSquareUnder()->IncStaticAnimatedEntities();
1176 SendNewDrawAndMemorizedUpdateRequest();
1180 void item::SendNewDrawAndMemorizedUpdateRequest() const
1182 if(!game::IsInWilderness())
1183 for(int c
= 0; c
< SquaresUnder
; ++c
)
1186 lsquare
*Square
= GetLSquareUnder(c
);
1188 Square
->SendNewDrawRequest();
1189 Square
->SendMemorizedUpdateRequest();
1194 void item::CalculateEmitation()
1196 object::CalculateEmitation();
1199 for(int c
= 0; c
< /*SquaresUnder*/FluidCount
; ++c
)
1200 for(const fluid
* F
= Fluid
[c
]; F
; F
= F
->Next
)
1201 game::CombineLights(Emitation
, F
->GetEmitation());
1204 void item::FillFluidVector (fluidvector
&Vector
, int SquareIndex
) const {
1206 if (SquareIndex
< 0 || SquareIndex
>= FluidCount
) ABORT("item::FillFluidVector(): invalid SquareIndex: %d\n", SquareIndex
);
1207 for (fluid
*F
= Fluid
[SquareIndex
]; F
; F
= F
->Next
) Vector
.push_back(F
);
1211 void item::SpillFluid(character
*, liquid
* Liquid
, int SquareIndex
)
1213 if(AllowFluids() && Liquid
->GetVolume())
1214 AddFluid(Liquid
, "", SquareIndex
, false);
1219 void item::TryToRust (sLong LiquidModifier
) {
1220 if (MainMaterial
->TryToRust(LiquidModifier
)) {
1221 if (CanBeSeenByPlayer()) {
1222 if (MainMaterial
->GetRustLevel() == NOT_RUSTED
) ADD_MESSAGE("%s rusts.", CHAR_NAME(DEFINITE
));
1223 else ADD_MESSAGE("%s rusts more.", CHAR_NAME(DEFINITE
));
1225 MainMaterial
->SetRustLevel(MainMaterial
->GetRustLevel() + 1);
1229 void item::CheckFluidGearPictures(v2 ShadowPos
, int SpecialFlags
, truth BodyArmor
)
1232 for(fluid
* F
= Fluid
[0]; F
; F
= F
->Next
)
1233 F
->CheckGearPicture(ShadowPos
, SpecialFlags
, BodyArmor
);
1236 void item::DrawFluidGearPictures(blitdata
& BlitData
, int SpecialFlags
) const
1239 for(const fluid
* F
= Fluid
[0]; F
; F
= F
->Next
)
1240 F
->DrawGearPicture(BlitData
, SpecialFlags
);
1243 void item::DrawFluidBodyArmorPictures(blitdata
& BlitData
, int SpecialFlags
) const
1246 for(const fluid
* F
= Fluid
[0]; F
; F
= F
->Next
)
1247 F
->DrawBodyArmorPicture(BlitData
, SpecialFlags
);
1250 void item::DrawFluids(blitdata
& BlitData
) const
1252 cint SquareIndex
= BlitData
.CustomData
& SQUARE_INDEX_MASK
;
1254 for(const fluid
* F
= Fluid
[SquareIndex
]; F
; F
= F
->Next
)
1258 void item::ReceiveAcid(material
*, cfestring
&, sLong Modifier
)
1260 if(GetMainMaterial()->GetInteractionFlags() & CAN_DISSOLVE
)
1262 int Damage
= Modifier
/ 1000;
1266 Damage
+= RAND() % Damage
;
1267 ReceiveDamage(0, Damage
, ACID
);
1272 void item::DonateFluidsTo(item
* Item
)
1275 for(int c
= 0; c
< GetSquaresUnder(); ++c
)
1276 for(fluid
* F
= Fluid
[c
]; F
; F
= F
->Next
)
1278 liquid
* Liquid
= F
->GetLiquid();
1279 Item
->AddFluid(Liquid
->SpawnMoreLiquid(Liquid
->GetVolume()), F
->GetLocationName(), c
, F
->IsInside());
1283 void item::Destroy(character
* Destroyer
, int)
1285 if(CanBeSeenByPlayer())
1286 ADD_MESSAGE("%s is destroyed.", GetExtendedDescription().CStr());
1288 if(Destroyer
&& IsOnGround())
1290 room
* Room
= GetRoom();
1293 Room
->HostileAction(Destroyer
);
1296 truth Equipped
= PLAYER
->Equips(this);
1301 game::AskForEscPress(CONST_S("Equipment destroyed!"));
1304 void item::RemoveRust()
1306 for(int c
= 0; c
< GetMaterials(); ++c
)
1308 GetMaterial(c
)->SetRustLevel(NOT_RUSTED
);
1311 void item::SetSpoilPercentage(int Value
)
1313 for(int c
= 0; c
< GetMaterials(); ++c
)
1315 material
* Material
= GetMaterial(c
);
1317 if(Material
&& Material
->CanSpoil())
1318 Material
->SetSpoilCounter(Material
->GetSpoilModifier() * Value
/ 100);
1322 void item::RedistributeFluids()
1325 for(int c
= 0; c
< GetSquaresUnder(); ++c
)
1326 for(fluid
* F
= Fluid
[c
]; F
; F
= F
->Next
)
1330 material
* item::GetConsumeMaterial(ccharacter
* Consumer
, materialpredicate Predicate
) const
1332 return (MainMaterial
->*Predicate
)() && Consumer
->CanConsume(MainMaterial
) ? MainMaterial
: 0;
1335 /* The parameter can only be MainMaterial */
1337 material
* item::RemoveMaterial(material
*)
1344 void item::InitMaterials(material
* FirstMaterial
, truth CallUpdatePictures
)
1346 InitMaterial(MainMaterial
, FirstMaterial
, GetDefaultMainVolume());
1347 SignalVolumeAndWeightChange();
1349 if(CallUpdatePictures
)
1353 void item::GenerateMaterials()
1355 int Chosen
= RandomizeMaterialConfiguration();
1356 const fearray
<sLong
>& MMC
= GetMainMaterialConfig();
1357 InitMaterial(MainMaterial
,
1358 MAKE_MATERIAL(MMC
.Data
[MMC
.Size
== 1 ? 0 : Chosen
]),
1359 GetDefaultMainVolume());
1362 void item::SignalSquarePositionChange(int Position
)
1364 Flags
&= ~SQUARE_POSITION_BITS
;
1365 Flags
|= Position
<< SQUARE_POSITION_SHIFT
;
1368 truth
item::Read(character
* Reader
)
1370 Reader
->StartReading(this, GetReadDifficulty());
1374 truth
item::CanBeHardened(ccharacter
*) const
1376 return MainMaterial
->GetHardenedMaterial(this) != NONE
;
1379 void item::SetLifeExpectancy(int Base
, int RandPlus
)
1381 LifeExpectancy
= RandPlus
> 1 ? Base
+ RAND_N(RandPlus
) : Base
;
1385 truth
item::IsVeryCloseToSpoiling() const
1387 for(int c
= 0; c
< GetMaterials(); ++c
)
1388 if(GetMaterial(c
) && !GetMaterial(c
)->IsVeryCloseToSpoiling())
1394 truth
item::IsValuable() const
1396 if(DataBase
->IsValuable
)
1399 for(int c
= 0; c
< GetMaterials(); ++c
)
1401 material
* M
= GetMaterial(c
);
1403 if(M
&& M
->GetCommonFlags() & IS_VALUABLE
)
1410 int item::GetHinderVisibilityBonus(ccharacter
* Char
) const
1414 if(GetGearStates() & INFRA_VISION
1415 && !Char
->TemporaryStateIsActivated(INFRA_VISION
))
1418 if(GetGearStates() & ESP
1419 && !Char
->TemporaryStateIsActivated(ESP
))
1422 if(!game::IsDark(GetEmitation()))
1428 sLong
item::GetFixPrice() const
1430 item
* Clone
= GetProtoType()->Clone(this);
1431 Clone
= Clone
->Fix();
1432 Clone
->RemoveRust();
1433 sLong FixPrice
= Clone
->GetTruePrice();
1434 Clone
->SendToHell();
1435 return Max(sLong(3.5 * sqrt(FixPrice
)), 10);
1438 void item::AddTrapName(festring
& String
, int Amount
) const
1441 AddName(String
, DEFINITE
);
1444 String
<< Amount
<< ' ';
1445 AddName(String
, PLURAL
);
1449 truth
item::Spoils() const
1451 for(int c
= 0; c
< GetMaterials(); ++c
)
1453 cmaterial
* Material
= GetMaterial(c
);
1455 if(Material
&& Material
->Spoils())
1462 int item::GetMaxSpoilPercentage() const
1464 int MaxPercentage
= 0;
1466 for(int c
= 0; c
< GetMaterials(); ++c
)
1468 cmaterial
* Material
= GetMaterial(c
);
1471 MaxPercentage
= Max(MaxPercentage
, Material
->GetSpoilPercentage());
1474 return MaxPercentage
;
1477 truth
item::HasPrice() const
1479 return GetPrice() || GetMaterialPrice();
1482 void item::Disappear()
1488 outputfile
& operator<<(outputfile
& SaveFile
, const idholder
* IdHolder
)
1490 SaveFile
<< IdHolder
->ID
;
1494 inputfile
& operator>>(inputfile
& SaveFile
, idholder
*& IdHolder
)
1496 IdHolder
= new idholder(ReadType(feuLong
, SaveFile
));
1500 festring
item::GetExtendedDescription() const
1502 if(!CanBeSeenByPlayer())
1503 return CONST_S("something");
1506 ccharacter
* Carrier
= FindCarrier();
1510 if(Carrier
->IsPlayer())
1513 AddName(Desc
, UNARTICLED
);
1516 else if(Carrier
->CanBeSeenByPlayer())
1518 Carrier
->AddName(Desc
, DEFINITE
);
1520 AddName(Desc
, UNARTICLED
);
1525 AddName(Desc
, DEFINITE
);
1528 GetLSquareUnder()->AddLocationDescription(Desc
);
1533 ccharacter
* item::FindCarrier() const
1535 return Slot
[0]->FindCarrier();
1538 /* returns 0 if not worn or wielded else the wearer */
1540 const character
* item::GetWearer() const
1542 if(!GetSlot()->IsGearSlot())
1545 return FindCarrier();
1548 void itemlock::PostConstruct()
1550 /* Terrible gum solution! */
1552 if(!(GetVirtualConfig() & LOCK_BITS
))
1554 int NormalLockTypes
= 0;
1555 const itemdatabase
*const* ConfigData
= GetVirtualProtoType()->GetConfigData();
1556 int c
, ConfigSize
= GetVirtualProtoType()->GetConfigSize();
1558 for(c
= 0; c
< ConfigSize
; ++c
)
1559 if(ConfigData
[c
]->Config
& LOCK_BITS
1560 && (ConfigData
[c
]->Config
& ~LOCK_BITS
) == GetVirtualConfig()
1561 && !(ConfigData
[c
]->Config
& S_LOCK_ID
))
1564 int ChosenLock
= RAND() % NormalLockTypes
;
1566 for(c
= 0; c
< ConfigSize
; ++c
)
1567 if(ConfigData
[c
]->Config
& LOCK_BITS
1568 && (ConfigData
[c
]->Config
& ~LOCK_BITS
) == GetVirtualConfig()
1569 && !(ConfigData
[c
]->Config
& S_LOCK_ID
)
1572 SetVirtualConfig(ConfigData
[c
]->Config
, NO_PIC_UPDATE
);
1578 truth
itemlock::TryKey(item
* Key
, character
* Applier
)
1580 if(GetVirtualConfig() & BROKEN_LOCK
)
1582 ADD_MESSAGE("The lock is broken.");
1586 if(Key
->CanOpenLockType(GetVirtualConfig()&LOCK_BITS
))
1590 if(Applier
->IsPlayer())
1591 ADD_MESSAGE("You unlock %s.", GetVirtualDescription(DEFINITE
).CStr());
1592 else if(Applier
->CanBeSeenByPlayer())
1593 ADD_MESSAGE("%s unlocks %s.", Applier
->CHAR_NAME(DEFINITE
), GetVirtualDescription(DEFINITE
).CStr());
1597 if(Applier
->IsPlayer())
1598 ADD_MESSAGE("You lock %s.", GetVirtualDescription(DEFINITE
).CStr());
1599 else if(Applier
->CanBeSeenByPlayer())
1600 ADD_MESSAGE("%s locks %s.", Applier
->CHAR_NAME(DEFINITE
), GetVirtualDescription(DEFINITE
).CStr());
1607 if(Applier
->IsPlayer())
1608 ADD_MESSAGE("%s doesn't fit in the lock.", Key
->CHAR_NAME(DEFINITE
));
1609 else if(Applier
->CanBeSeenByPlayer())
1610 ADD_MESSAGE("%s tries to fit %s in the lock, but fails.", Applier
->CHAR_NAME(DEFINITE
), Key
->CHAR_NAME(DEFINITE
));
1616 void itemlock::Save(outputfile
& SaveFile
) const
1621 void itemlock::Load(inputfile
& SaveFile
)
1626 truth
item::IsBeverage(ccharacter
*) const
1628 for(int c
= 0; c
< GetMaterials(); ++c
)
1630 cmaterial
* Material
= GetMaterial(c
);
1632 if(Material
&& (Material
->GetCategoryFlags() & IS_BEVERAGE
))
1643 SendMemorizedUpdateRequest();
1649 ItemFlags
&= ~HASTE
;
1650 SendMemorizedUpdateRequest();
1653 void item::SendMemorizedUpdateRequest() const
1655 if(!game::IsInWilderness())
1656 for(int c
= 0; c
< SquaresUnder
; ++c
)
1659 lsquare
* Square
= GetLSquareUnder(c
);
1660 Square
->SendMemorizedUpdateRequest();
1665 truth
item::AddStateDescription (festring
& Name
, truth Articled
) const {
1668 if ((ItemFlags
&(HASTE
|SLOW
)) && Articled
) { res
= true; Name
<< "a "; }
1669 if (ItemFlags
&HASTE
) { res
= true; Name
<< "hasted "; }
1670 if (ItemFlags
&SLOW
) { res
= true; Name
<< "slowed "; }
1676 truth
item::Burn (character
*who
, v2 where
, int dir
) {
1677 //who->EditExperience(PERCEPTION, 150, 1 << 10);
1678 where
+= game::GetMoveVector(dir
);
1679 area
*ca
= who
->GetSquareUnder()->GetArea();
1680 if (where
.X
< 0 || where
.Y
< 0 || where
.X
>= ca
->GetXSize() || where
.Y
>= ca
->GetYSize()) return false;
1681 lsquare
*sq
= static_cast<lsquare
*>(ca
->GetSquare(where
.X
, where
.Y
));
1683 sq
->ReceiveTrapDamage(who
, 50, FIRE
, dir
);