Jump to content

Chokboyz

Member
  • Posts

    428
  • Joined

  • Last visited

    Never

Everything posted by Chokboyz

  1. Quote: While you're working on the automap, sometimes, when I move next to water, one edge of the water will be replaced with the tile that's next to it on the automap. I couldn't reproduce that myself. So either it is fixed by the previous changes or i didn't do the right thing. Either way, feel free to test the new executable to see if the bug is always present. Quote: Also, terrains that emit light are strange colored blocks on the automap, rather than small representations of themselves. Strange, on my automap it is actually small representation of themselves (no red or purple block)... Did I miss the point ? To Ishad Nha and Thuryl : Monster 0 problem added to the to-do list Chokboyz
  2. Quote: Seems that i some cases the src or dest rectangle into rect_draw_some_item have negative values In the GRAPHUTL.cpp, function rect_draw_some_item() lines 106-109 Click to reveal.. StretchBlt(hdcMem3,dest_rect.left,dest_rect.top,dest_rect.right - dest_rect.left, dest_rect.bottom - dest_rect.top, hdcMem2,0,0,src_rect.right - src_rect.left, src_rect.bottom - src_rect.top,SRCAND); should read Click to reveal.. StretchBlt(hdcMem3,dest_rect.left,dest_rect.top,dest_rect.right - dest_rect.left, dest_rect.bottom - dest_rect.top, hdcMem2,0,0,dest_rect.right - dest_rect.left, dest_rect.bottom - dest_rect.top,SRCAND); because the hdcMem2 handler is initialized at dest_rect size and read at src_size. The same error is present in the function, few lines later (lines 145-148 for Windows) and needs to be fixed too. The result in Windows was that custom graphics who were not standard size were giving gibberish (white "noise") when masking them in the inventory. Maybe that is what causes your error. I was wondering, since you made OBoE use SDL for sound, if you considered trying to implement a cross-platform (wxWidget, QT4.5, ...) GUI. If you did, that would be great as, when done, we could fusion the two codes (Bug Fixes, New Features and Cross-Platform support). I've given it a try, but i was far out of my league I may well understand that you are fed up with all of this though Edit : Found this in the previous posts : Quote: As for wxwidgets and QT, they are more C++ centered and hence didnt feel right for this. This answer my last question So, nevermind ... Hope it helps, Chokboyz
  3. This line got somehow squished in 1), it is now fixed. Quote: If the hit roll is less or equal to the "value_of_weapon_skill" index in the following array (size 51) : {20,30,40,45,50,55,60,65,69,73,77,81,84,87,90,92,94,96,97,98,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99} you hit. Else you miss, play the animation and miss sound and goes on to C. Thanks, Chokboyz Edit : was missing a line in C, with modified hit roll formula, fixed Quote: hit_roll = get_ran(1,0,100) + hit_adj - 5 * weapon2_bonus + 5 * (adventurerWebsLevel / 3)
  4. Another quick bug-fix : Quote: (Miramor,CM)Fix automap updating so that changes in terrain will appear on the automap. Notice that this bug only happens in town (outside the terrain is changed on the automap automatically). We need to do a full automap redraw as soon as the terrain is changed/swapped/transformed to fix this (as when the player close and reopen the automap). To do so, open file SPECIALS.cpp, find function townmode_spec() and insert the line draw_map(modeless_dialogs[5],10); after lines 2337, 2344 and 2349 (the lines saying *redraw = 1;, in case 171, 172 and 173). The 10 parameter in draw_map() forces the full update of the automap. Others values of interest : 5 (default) redraw adjacents to party terrains and 11 blanks everything except adjacents terrains (sort of "empty map" ...). Chokboyz
  5. In this post, I will try, as asked, to describe what happens (code wise) when you attacks a monster (when a monster attacks you or another monster, it is quite different as some things are simplified and others not ...). To do so, i will explicit the two fonctions used in the process pc_attack() in COMBAT.cpp and damage_monst() in SPECIALS.cpp. The original (windows) code is used for accuracy. Before beginning, here are two things one should know : The minmax(a,b,c) function returns a if c<a ; b if c>b or c if he is in between (with a<. The function get_ran(c,a, returns a random number between a x c and b x c. The Bless/Curse level of a monster or a character is the same variable with positive value being blessed and negative value being cursed (the same is true with haste/slow, ...) Here we go ... Hitting a monster (pc_attack())First if the adventurer is absent/dead/dust/stone/whatever_except_here_and_sound or if the adventurer is sleepy or paralysed, don't do a thing. Then checks the weapon(s) equipped by the pc Calculate the hit_adj (hit adjustement) following the formula hit_adj = (-5 * minmax(-8,8,AdventurerBlessLevel)) + 5 * minmax(-8,8,MonsterBlessLevel)- stat_adj(value_of_dexterity) * 5 + (Adventurer_encumberance) * 5; Here, the stat_adj is the "value_of_dexterity" index in the following array (begins at 0) : {-3,-3,-2,-1,0,0,1,1,1,2,2,2,3,3,3,3,4,4,4,5,5} Calculate the dmg_adj (damage adjustement) following the formula dam_adj = minmax(-8,8,AdventurerBlessLevel) - minmax(-8,8,MonsterBlessLevel)+ stat_adj(value_of_strength); Here, the stat_adj is the "value_of_strength" index in the following array (begins at 0) : {-3,-3,-2,-1,0,0,1,1,1,2,2,2,3,3,3,3,4,4,4,5,5} , plus one if the character has the Exceptional Strength trait. If the target is sleepy or paralysed, substract 80 to hit_adj and add 10 to dmg_adj. If the attacker has an item with the skill ability equipped, add 5 * (item_level / 2 + 1); to hit_adj and item_level / 2 to dmg_adj. If the attacker has an item with the giant strength ability equipped, add item_level * 2 to hit_adj and item_level to dmg_adj. Negates sanctuary for the attacker Then it depends of the weapon(s) equippedIf weaponless, you punch. The hit roll is calculated following the formula : hit_roll = get_ran(1,0,100) + hit_adj - 20+5 * (adventurerWebsLevel / 3) The damage roll is calculated following the formula : dmg_roll= get_ran(1,1,4) + dam_adj; If the hit roll is less or equal to the "value_of_dexterity" index in the following array (size 51) : {20,30,40,45,50,55,60,65,69,73,77,81,84,87,90,92,94,96,97,98,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99} you hit and call the damage_monst() function with dmg_roll as parameter. You've got at least one weapon. It first get the type of weapon you wield. Then, the hit roll is calculated following the formula : hit_roll = get_ran(1,0,100) - 5 + hit_adj - 5 * weapon1_bonus + 5 * (adventurerWebsLevel / 3) If you wield a second weapon without having the ambidextrous trait, add 25 to hit_roll. If you are a slith wielding a pole weapon, substract 10 to hit_roll. The damage roll is then calculated following the formula : dmg_roll = get_ran(1,1,weapon1_level) + dam_adj + 2 + weapon1_bonus If the weapon has the weak weapon ability the damage roll becomes dmg_roll * (10 - weapon1.ability_strength) / 10 If the hit roll is less or equal to the "value_of_weapon_skill" index in the following array (size 51) : {20,30,40,45,50,55,60,65,69,73,77,81,84,87,90,92,94,96,97,98,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99} you hit. Else you miss, play the animation and miss sound and goes on to C. Then it calculates special damage (spec_dam) depending of the weapon ability For a flaming weapon, spec_dam = get_ran(WeaponAbilityLevel,1,6). For a demon slayer weapon, spec_dam = 8 * WeaponAbilityLevel if the monster is a demon. For a undead slayer weapon, spec_dam = 6 * WeaponAbilityLevel if the monster is an undead. For a lizard slayer weapon, spec_dam = 5 * WeaponAbilityLevel if the monster is a reptile. For a giant slayer weapon, spec_dam = 8 * WeaponAbilityLevel if the monster is a giant. For a mage slayer weapon, spec_dam = 4 * WeaponAbilityLevel if the monster is a mage. For a priest slayer weapon, spec_dam = 4 * WeaponAbilityLevel if the monster is a priest. For a bug slayer weapon, spec_dam = 7 * WeaponAbilityLevel if the monster is a bug. If it is a cause fear weapon, it reduces the morale of the monster by 10 * WeaponAbilityLevel if the monster doesn't absorb spell or is magic immuned. If magic resistant, it reduces the morale of the monster by 5 * WeaponAbilityLevel (no spec_dam). Then it checks if you assassinate. To assassinate, the level of the pc must be more or equal to the level of the monster minus 1, his skill in assassination must be more or equal to the level of the monster divided by 2 and the monster mustn't be a splitter (can't assassinate a splitter). Then if get_ran(1,0,100) < hit_chance[max(AdventurerAssassinationSkill - MonsterLevel),0)], where hit_chance is the same array as in A, you effectively assassinate and add the dmg_roll to spec_dmg. And finally it damages the monster by calling damage_monst() (see 2 below). After dealing damages, if the pc has poison on his weapon, the poison level (+2 if he has a poison augment item equipped) on his blade is added to the monster poison counter and the poison level on the blade is reduced. Then if the weapon is a poisoned weapon (the ability), it has 1 chance out of 2 to poison the monster with (WeaponAbilityLevel /2) poison level. If the weapon is an acid weapon (the ability), it has 1 chance out of 2 to put acid on the monster with (WeaponAbilityLevel /2) acid level. If the weapon is a soulsucker weapon (the ability), it has 1 chance out of 2 to heal the pc (WeaponAbilityLevel /2) health. You have a second weapon equipped. It does exactely the same thing a second time except : No race slith adjustment for pole weapon equipped The hit roll is calculated following the formula : hit_roll = get_ran(1,0,100) + hit_adj - 5 * weapon2_bonus + 5 * (adventurerWebsLevel / 3) The damage roll is calculated following the formula : dmg_roll = get_ran(1,1,weapon2_level) + dam_adj - 1 + weapon2_bonus There is no assassination, nor poison with the second weapon. It reduces poison on blades (once more), take 4 AP away and finally if the monster has martyr's shield (spell or ability) on and is not killed it damages the pc by the amount of damage done to the monster. Damaging a monster (damage_monst()) The parameters are dmg_roll (amount of damage) and spec_dmg (amount of special damage, i.e item ability, ...). First if the monster is resistant to the type of damage, the dmg_roll is divided by 2 ; if it's immuned dmg_roll is reduced to 0. Then if the monster absorb magic and the damage type is fire, magic or cold, add dmg_roll to monster's health and stop here. If damage type is fire or cold, and if get_ran(1,0,20) <= MonsterLevel, then dmg_roll is divided by 2. If damage type is magic, and if get_ran(1,0,24) <= MonsterLevel, then dmg_roll is divided by 2. If the monster has the invulnerable ability (a.k.a Rentar-Ihrno in the code), then dmg_roll is divided by 10. The Armor Roll of the monster is calculated following the formula : armor_roll = get_ran(1,0,(MonsterArmor * 5/4)) + MonsterLevel / 4; If the damage type is weapon (and only weapon ; undead and demons bypass this. Thanks Thuryl) substract armor_roll to dmg_roll. Then if dmg_roll is greater than 0 (dmg_roll + spec_dmg) are deduced to the monster health. If dmg_roll is less or equal to 0, no damage is done and the function stop here (no special damage). Then if it is a splitting monster, split it. Updates the party damage statistic and make the monster hostile and active (a monster see you-like). The splash animation is done and the monster is killed if it health is strictly lesser (<) then 0 If the monster is alive, it reduces its morale by 1 if damages done is between 1 and 5, 2 if 6 and 10, 3 if 10 and 20 or 5 if greater than 20. Finally, if you damaged an innocent make the town hostile. I may have overlooked something since it's a long list of thing, but everything essential should be here. Chokboyz
  6. The typos have been fixed and SLEEP_CLOUD has been changed to SLEEP_FIELD to match description. I did find the statAdj() function in the code (thanks) and the older stat_adj should indeed be removed (the item 99 bug is also present in statAdj ... what ability should replace this, skill ? will ?). Thanks for cross-checking the values, Chokboyz
  7. You are right, i didn't find a 99 ability either. Seems like another bug in the code (i confirm your finding that demons does undead damages and vice versa). Oddly, i can't find the same function (stat_adj()) in ormus' build (the declaration is here but can't find the function). I finally complete the CONSTS.h file and put it here for anyone to use. Maybe you can confirm the values since you seems to have done the same Click to reveal.. (CONSTS.h) #ifndef _CONSTS_H #define _CONSTS_H /* This file contain numerous constans in form of #defines. Almost all of this constants cannot be changed because that would make the game work improperly. */ #define NUM_OF_PCS 6 #define INVALID_PC NUM_OF_PCS #define INVALID_TOWN 200 #define NUM_OF_BOATS 30 #define NUM_OF_HORSES 30 #define SFX_SMALL_BLOOD 1 #define SFX_MEDIUM_BLOOD 2 #define SFX_LARGE_BLOOD 4 #define SFX_SMALL_SLIME 8 #define SFX_BIG_SLIME 16 #define SFX_ASH 32 #define SFX_BONES 64 #define SFX_RUBBLE 128 /* stuff done flags */ #define SDF_IS_PARTY_SPLIT 304][0 #define SDF_PARTY_SPLIT_X 304][1 #define SDF_PARTY_SPLIT_Y 304][2 #define SDF_NO_INSTANT_HELP 306][4 // boolean /* overall mode */ #define MODE_OUTDOORS 0 #define MODE_TOWN 1 #define MODE_TALK_TOWN 2 // looking for someone to talk #define MODE_COMBAT 10 #define MODE_FIRING 12 // firing from bow or crossbow #define MODE_THROWING 13 // throwing missle #define MODE_DROPPING 15 #define MODE_TALKING 20 #define MODE_SHOPPING 21 #define MODE_LOOK_OUTDOORS 35 // looking at something #define MODE_LOOK_TOWN 36 #define MODE_LOOK_COMBAT 37 /* adven.main_status */ //complete #define MAIN_STATUS_ABSENT 0 // absent, empty slot #define MAIN_STATUS_ALIVE 1 #define MAIN_STATUS_DEAD 2 #define MAIN_STATUS_DUST 3 #define MAIN_STATUS_STONE 4 #define MAIN_STATUS_FLED 5 #define MAIN_STATUS_SURFACE 6 // fled to surface? #define MAIN_STATUS_WON 7 /* main status modifiers */ #define MAIN_STATUS_SPLIT 10 // split from party /* adven.skills */ //complete #define SKILL_STRENGTH 0 #define SKILL_DEXTERITY 1 #define SKILL_INTELLIGENCE 2 #define SKILL_EDGED_WEAPONS 3 #define SKILL_BASHING_WEAPONS 4 #define SKILL_POLE_WEAPONS 5 #define SKILL_THROWN_MISSILES 6 #define SKILL_ARCHERY 7 #define SKILL_DEFENSE 8 #define SKILL_MAGE_SPELLS 9 #define SKILL_PRIEST_SPELLS 10 #define SKILL_MAGE_LORE 11 #define SKILL_ALCHEMY 12 #define SKILL_ITEM_LORE 13 #define SKILL_DISARM_TRAPS 14 #define SKILL_LOCKPICKING 15 #define SKILL_ASSASSINATION 16 #define SKILL_POISON 17 #define SKILL_LUCK 18 /* adven.traits */ //complete #define TRAIT_TOUGHNESS 0 #define TRAIT_MAGICALLY_APT 1 #define TRAIT_AMBIDEXTROUS 2 #define TRAIT_NIMBLE 3 #define TRAIT_CAVE_LORE 4 #define TRAIT_WOODSMAN 5 #define TRAIT_GOOD_CONST 6 #define TRAIT_HIGHLY_ALERT 7 #define TRAIT_EXCEPTIONAL_STRENGTH 8 #define TRAIT_RECUPERATION 9 #define TRAIT_SLUGGISH 10 #define TRAIT_MAGICALLY_INEPT 11 #define TRAIT_FRAIL 12 #define TRAIT_CHRONIC_DISEASE 13 #define TRAIT_BAD_BACK 14 /* adven.race */ //complete #define RACE_HUMAN 0 #define RACE_NEPHIL 1 #define RACE_SLITH 2 /* adven.status*/ //complete - assign a positive value for a help pc effect, a negative for harm pc #define STATUS_POISONED_WEAPON 0 #define STATUS_BLESS 1 #define STATUS_POISON 2 #define STATUS_HASTE 3 #define STATUS_INVULNERABLE 4 #define STATUS_MAGIC_RESISTANCE 5 #define STATUS_WEBS 6 #define STATUS_DISEASE 7 #define STATUS_INVISIBLE 8 //sanctuary #define STATUS_DUMB 9 #define STATUS_MARTYRS_SHIELD 10 #define STATUS_ASLEEP 11 #define STATUS_PARALYZED 12 #define STATUS_ACID 13 /* damage type*/ /* used as parameter to some functions */ #define DAMAGE_WEAPON 0 #define DAMAGE_FIRE 1 #define DAMAGE_POISON 2 #define DAMAGE_MAGIC 3 #define DAMAGE_UNBLOCKABLE 4 //from the source files - the display is the same as the magic one (damage_monst in SPECIALS.cpp or pc_record_type::runTrap in PARTY.cpp) #define DAMAGE_COLD 5 #define DAMAGE_UNDEAD 6 //from the source files - the display is the same as the weapon one #define DAMAGE_DEMON 7 //from the source files - the display is the same as the weapon one // 8 and 9 aren't defined : doesn't print any damage. According to the source files the 9 is DAMAGE_MARKED though. Wrong ? #define DAMAGE_MARKED 10 // usage: DAMAGE_MARKED + damage_type #define DAMAGE_NO_PRINT 30 // usage: DAMAGE_NO_PRINT + damage_type /* trap type */ /* used in pc_record_type::runTrap(...) */ #define TRAP_RANDOM 0 #define TRAP_BLADE 1 #define TRAP_DART 2 #define TRAP_GAS 3 // poisons all #define TRAP_EXPLOSION 4 // damages all => uses c_town.difficulty rather than trap_level to calculates damages (and even c_town.difficulty /13). #define TRAP_SLEEP_RAY 5 #define TRAP_NO_TRAP_AFTER_ALL 6 #define TRAP_DRAIN_XP 7 #define TRAP_ALERT 8 // makes town hostile #define TRAP_FLAMES 9 // damages all => uses trap_level (*5) to calculates damages. #define TRAP_DUMBFOUND 10 //dumbfound all #define TRAP_DISEASE 11 #define TRAP_DISEASE_ALL 12 /* items.type a.k.a type of weapon */ #define ITEM_EDGED 1 #define ITEM_BASHING 2 #define ITEM_POLE 3 /* items.variety a.k.a item type (in editor) */ #define ITEM_TYPE_NO_ITEM 0 //a guess, i can't test it ; but should be accurate => confirmed by the code #define ITEM_TYPE_ONE_HANDED 1 #define ITEM_TYPE_TWO_HANDED 2 #define ITEM_TYPE_GOLD 3 //a guess, i can't test it ; but should be accurate => confirmed by the code #define ITEM_TYPE_BOW 4 #define ITEM_TYPE_ARROW 5 #define ITEM_TYPE_THROWN_MISSILE 6 #define ITEM_TYPE_POTION 7 // potion/magic item #define ITEM_TYPE_SCROLL 8 // scroll/magic item #define ITEM_TYPE_WAND 9 #define ITEM_TYPE_TOOL 10 #define ITEM_TYPE_FOOD 11 //a guess, i can't test it ; but should be accurate => confirmed by the code #define ITEM_TYPE_SHIELD 12 #define ITEM_TYPE_ARMOR 13 #define ITEM_TYPE_HELM 14 #define ITEM_TYPE_GLOVES 15 #define ITEM_TYPE_SHIELD_2 16 //don't know why a second type of shield is used ; it is actually checked in the armor code (item >= 12 and <= 17) #define ITEM_TYPE_BOOTS 17 //(continued) and you can't equip another (12) shield while wearing it ... I didn't find a single item with this property in the bladbase.exs ... #define ITEM_TYPE_RING 18 #define ITEM_TYPE_NECKLACE 19 #define ITEM_TYPE_WEAPON_POISON 20 #define ITEM_TYPE_NON_USE_OBJECT 21 #define ITEM_TYPE_PANTS 22 #define ITEM_TYPE_CROSSBOW 23 #define ITEM_TYPE_BOLTS 24 #define ITEM_TYPE_MISSILE_NO_AMMO 25 //e.g slings /* items.ability */ /* Weapons Ability */ #define ITEM_NO_ABILITY 0 #define ITEM_FLAMING_WEAPON 1 #define ITEM_DEMON_SLAYER 2 #define ITEM_UNDEAD_SLAYER 3 #define ITEM_LIZARD_SLAYER 4 #define ITEM_GIANT_SLAYER 5 #define ITEM_MAGE_SLAYER 6 #define ITEM_PRIEST_SLAYER 7 #define ITEM_BUG_SLAYER 8 #define ITEM_ACIDIC_WEAPON 9 #define ITEM_SOULSUCKER 10 #define ITEM_DRAIN_MISSILES 11 #define ITEM_WEAK_WEAPON 12 #define ITEM_CAUSES_FEAR 13 #define ITEM_POISONED_WEAPON 14 /* General Ability */ #define ITEM_PROTECTION 30 #define ITEM_FULL_PROTECTION 31 #define ITEM_FIRE_PROTECTION 32 #define ITEM_COLD_PROTECTION 33 #define ITEM_POISON_PROTECTION 34 #define ITEM_MAGIC_PROTECTION 35 #define ITEM_ACID_PROTECTION 36 #define ITEM_SKILL 37 #define ITEM_STRENGTH 38 #define ITEM_DEXTERITY 39 #define ITEM_INTELLIGENCE 40 #define ITEM_ACCURACY 41 #define ITEM_THIEVING 42 #define ITEM_GIANT_STRENGTH 43 #define ITEM_LIGHTER_OBJECT 44 #define ITEM_HEAVIER_OBJECT 45 #define ITEM_OCCASIONAL_BLESS 46 #define ITEM_OCCASIONAL_HASTE 47 #define ITEM_LIFE_SAVING 48 #define ITEM_PROTECTION_FROM_PETRIFY 49 #define ITEM_REGENERATE 50 #define ITEM_POISON_AUGMENT 51 #define ITEM_DISEASE_PARTY 52 #define ITEM_WILL 53 #define ITEM_FREE_ACTION 54 #define ITEM_SPEED 55 #define ITEM_SLOW_WEARER 56 #define ITEM_PROTECTION_FROM_UNDEAD 57 #define ITEM_PROTECTION_FROM_DEMONS 58 #define ITEM_PROTECTION_FROM_HUMANOIDS 59 #define ITEM_PROTECTION_FROM_REPTILES 60 #define ITEM_PROTECTION_FROM_GIANTS 61 #define ITEM_PROTECTION_FROM_DISEASE 62 /* NonSpell Use ; the constant refers to both the positive and negative effect (don't mind the name). */ #define ITEM_POISON_WEAPON 70 //put poison on weapon #define ITEM_BLESS_USER 71 #define ITEM_CURE_POISON 72 #define ITEM_HASTE_USER 73 #define ITEM_ADD_INVULNERABILITY 74 #define ITEM_ADD_MAGIC_RESISTANCE 75 #define ITEM_ADD_WEB 76 #define ITEM_CAUSE_DISEASE 77 #define ITEM_ADD_SANCTUARY 78 #define ITEM_CAUSE_DUMBFOUND 79 #define ITEM_ADD_MARTYRS_SHIELD 80 #define ITEM_CURE_SLEEP 81 #define ITEM_CURE_PARALYSIS 82 #define ITEM_CURE_ACID 83 #define ITEM_BLISS 84 #define ITEM_ADD_EXPERIENCE 85 #define ITEM_ADD_SKILL_POINTS 86 #define ITEM_ADD_HEALTH 87 #define ITEM_ADD_SPELL_POINTS 88 #define ITEM_DOOM 89 #define ITEM_LIGHT 90 #define ITEM_STEALTH 91 #define ITEM_FIREWALK 92 #define ITEM_FLYING 93 #define ITEM_MAJOR_HEALING 94 /* Spell Usable */ #define ITEM_SPELL_FLAME 110 #define ITEM_SPELL_FIREBALL 111 #define ITEM_SPELL_FIRESTORM 112 #define ITEM_SPELL_KILL 113 #define ITEM_SPELL_ICE_BOLT 114 #define ITEM_SPELL_SLOW 115 #define ITEM_SPELL_SHOCKWAVE 116 #define ITEM_SPELL_DISPEL_UNDEAD 117 #define ITEM_SPELL_DISPEL_SPIRIT 118 #define ITEM_SPELL_SUMMONING 119 #define ITEM_SPELL_MASS_SUMMONING 120 #define ITEM_SPELL_ACID_SPRAY 121 #define ITEM_SPELL_STINKING_CLOUD 122 #define ITEM_SPELL_SLEEP_FIELD 123 #define ITEM_SPELL_VENOM 124 #define ITEM_SPELL_SHOCKSTORM 125 #define ITEM_SPELL_PARALYSIS 126 #define ITEM_SPELL_WEB_SPELL 127 #define ITEM_SPELL_STRENGTHEN_TARGET 128 //wand of carrunos effect #define ITEM_SPELL_QUICKFIRE 129 #define ITEM_SPELL_MASS_CHARM 130 #define ITEM_SPELL_MAGIC_MAP 131 #define ITEM_SPELL_DISPEL_BARRIER 132 #define ITEM_SPELL_MAKE_ICE_WALL 133 #define ITEM_SPELL_CHARM_SPELL 134 #define ITEM_SPELL_ANTIMAGIC_CLOUD 135 /* Reagents */ #define ITEM_HOLLY 150 // Holly/Toadstool #define ITEM_COMFREY_ROOT 151 #define ITEM_GLOWING_NETTLE 152 #define ITEM_CRYPT_SHROOM 153 // Crypt Shroom/Wormgr. #define ITEM_ASPTONGUE_MOLD 154 #define ITEM_EMBER_FLOWERS 155 #define ITEM_GRAYMOLD 156 #define ITEM_MANDRAKE 157 #define ITEM_SAPPHIRE 158 #define ITEM_SMOKY_CRYSTAL 159 #define ITEM_RESSURECTION_BALM 160 #define ITEM_LOCKPICKS 161 /* Missiles */ #define ITEM_MISSILE_RETURNING 170 #define ITEM_MISSILE_LIGHTNING 171 #define ITEM_MISSILE_EXPLODING 172 #define ITEM_MISSILE_ACID 173 #define ITEM_MISSILE_SLAY_UNDEAD 174 #define ITEM_MISSILE_SLAY_DEMON 175 #define ITEM_MISSILE_HEAL_TARGET 176 /* Monsters Stuff */ /* Skills Same as PC */ /* Monster Type */ #define MONSTER_TYPE_HUMAN 0 #define MONSTER_TYPE_REPTILE 1 #define MONSTER_TYPE_BEAST 2 #define MONSTER_TYPE_IMPORTANT 3 #define MONSTER_TYPE_MAGE 4 #define MONSTER_TYPE_PRIEST 5 #define MONSTER_TYPE_HUMANOID 6 #define MONSTER_TYPE_DEMON 7 #define MONSTER_TYPE_UNDEAD 8 #define MONSTER_TYPE_GIANT 9 #define MONSTER_TYPE_SLIME 10 #define MONSTER_TYPE_STONE 11 #define MONSTER_TYPE_BUG 12 #define MONSTER_TYPE_DRAGON 13 #define MONSTER_TYPE_MAGICAL_CREATURE 14 /* Attack Types */ #define MONSTER_ATTACK_SWINGS 0 #define MONSTER_ATTACK_CLAWS 1 #define MONSTER_ATTACK_BITES 2 #define MONSTER_ATTACK_SLIMES 3 #define MONSTER_ATTACK_PUNCHES 4 #define MONSTER_ATTACK_STINGS 5 #define MONSTER_ATTACK_CLUBS 6 #define MONSTER_ATTACK_BURNS 7 #define MONSTER_ATTACK_HARMS 8 #define MONSTER_ATTACK_STABS 9 /* Special Ability a.k.a spec_skill */ #define MONSTER_NO_SPECIAL_ABILITY 0 #define MONSTER_THROWS_DARTS 1 #define MONSTER_SHOOTS_ARROWS 2 #define MONSTER_THROWS_SPEARS 3 #define MONSTER_THROWS_ROCKS1 4 //4-24 damages #define MONSTER_THROWS_ROCKS2 5 //5-30 damages #define MONSTER_THROWS_ROCKS3 6 //6-36 damages #define MONSTER_THROWS_RAZORDISKS 7 #define MONSTER_PETRIFICATION_RAY 8 #define MONSTER_SP_DRAIN_RAY 9 //spell points drain ray #define MONSTER_HEAT_RAY 10 #define MONSTER_INVISIBLE 11 #define MONSTER_SPLITS 12 #define MONSTER_MINDLESS 13 #define MONSTER_BREATHES_STINKING_CLOUDS 14 #define MONSTER_ICY_TOUCH 15 #define MONSTER_XP_DRAINING_TOUCH 16 #define MONSTER_ICY_AND_DRAINING_TOUCH 17 #define MONSTER_SLOWING_TOUCH 18 #define MONSTER_SHOOTS_WEB 19 #define MONSTER_GOOD_ARCHER 20 #define MONSTER_STEALS_FOOD 21 #define MONSTER_PERMANENT_MARTYRS_SHIELD 22 #define MONSTER_PARALYSIS_RAY 23 #define MONSTER_DUMBFOUNDING_TOUCH 24 #define MONSTER_DISEASE_TOUCH 25 #define MONSTER_ABSORB_SPELLS 26 #define MONSTER_WEB_TOUCH 27 #define MONSTER_SLEEP_TOUCH 28 #define MONSTER_PARALYSIS_TOUCH 29 #define MONSTER_PETRIFICATION_TOUCH 30 #define MONSTER_ACID_TOUCH 31 #define MONSTER_BREATHES_SLEEP_CLOUDS 32 #define MONSTER_ACID_SPIT 33 #define MONSTER_SHOOTS_SPINES 34 #define MONSTER_DEATH_TOUCH 35 #define MONSTER_INVULNERABILITY 36 #define MONSTER_GUARD 37 /* Create Monsters/Fields */ #define MONSTER_NO_RADIATE 0 #define MONSTER_RADIATE_FIRE_FIELDS 1 #define MONSTER_RADIATE_ICE_FIELDS 2 #define MONSTER_RADIATE_SHOCK_FIELDS 3 #define MONSTER_RADIATE_ANTIMAGIC_FIELDS 4 #define MONSTER_RADIATE_SLEEP_FIELDS 5 #define MONSTER_RADIATE_STINKING_CLOUDS 6 //as said 7,8 and 9 are unused #define MONSTER_SUMMON1 10 //5 percent chance #define MONSTER_SUMMON2 11 //20 percent chance #define MONSTER_SUMMON3 12 //50 percent chance //as said 13 and 14 are unused #define MONSTER_DEATH_TRIGGERS 15 //death triggers global special #endif The formulas explanation is halfway done, the first part being the pc attacks a monster part. Chokboyz
  8. Quote: Combat.cpp is the major file for Windows here Right when it comes to hit something, but for damages it is done in SPECIALS.cpp (apparently needs some functions in there). Quote: Magically Apt I will have to research soon It is checked in the function pc_record_type::statAdj() in PC.cpp which return the skill adjustement to be used in the formulas. Click to reveal.. (explanation) short pc_record_type::statAdj(short which) { short tr; tr = skill_bonus[skills[which]]; //gets stat adjutment in the skill_bonus table (GLOBVAR.cpp) which correspond to the level in the which skill if (which == 2) { //if checked stat is intelligence if (traits[1] == TRUE) tr++; // if possess the Magically Apt. trait add one to tr if (hasAbilEquip(99) < 16) tr++; //add one to tr if has one item equipped with ability 99 => this ability is inexistant ... Bug probably ... } if (which == 0) // if checked stat is strengh if (traits[8] == TRUE) tr++; //if posses the Exceptional Strength, add one to tr return tr; } The whole process of hitting/damaging monster is almost decoded, but i will have to finish mapping item abilities to be completely accurate. I didn't looked into wands neither, but i think it also used the pc_cast() function. Hope it helps, Chokboyz
  9. Concerning the zoom-out problem : (Using latest Ormus' Scenario Editor Code) In file GRAPHICS.cpp, find the function draw_one_tiny_terrain_spot() (line 879) and do the following changes : Remove the lines 890 and 891 : if (picture_wanted >= 1000) picture_wanted = 74; (it's a check to print a black box if the graphic is custom) Replace the lines 917 and 918 : from_rect = get_custom_rect(picture_wanted % 1000); rect_draw_some_item(spec_scen_g, from_rect, ter_draw_gworld, dest_rect, 0, 0); by : SelectObject(hdc,store_bmp); from_rect = get_custom_rect(picture_wanted % 1000); rect_draw_some_item(spec_scen_g, from_rect, ter_draw_gworld, dest_rect, 0, 0); store_bmp = (HBITMAP)SelectObject(hdc,ter_draw_gworld); (store_bmp wasn't correctly selected in hdc ; last line is done to preserve compatibility with the rest of the function) The function rect_draw_some_item() in GRAPHUTL.cpp might needs some tweaking too, as if the custom graphics are not the exact same size then the base ones, gibberish may occurs. It's an hypothesis though, and i've not encountered anything like this in my tests ... Hope it helps, Chokboyz
  10. You're right once again ... Oddly, i didn't forget the if in the mac version of code Lacks of sleep i suppose ... Ok, i added the zoom-out problem to my to-do list Thanks again To ADoS : Quote: If that's what the demon/undead damage types are for, then how do items that protect from humanoids, lizards, and giants work? There are abilities for those too. I thought it would just check the monster type. It actually checks the type_of_attacker for the humanoids/reptiles/giants and the damage_type for normal/undead/demons. And it from the original sourcecode, not a homebrew one Click to reveal.. (proof) FILE : PARTY.cpp, function damage_pc() [...] if ((damage_type == 0) && ((level = get_prot_level(which_pc,30)) > 0)) how_much = how_much - level; if ((damage_type == 6) && ((level = get_prot_level(which_pc,57)) > 0)) how_much = how_much / ((level >= 7) ? 4 : 2); if ((damage_type == 7) && ((level = get_prot_level(which_pc,58)) > 0)) how_much = how_much / ((level >= 7) ? 4 : 2); if ((type_of_attacker == 6) && ((level = get_prot_level(which_pc,59)) > 0)) how_much = how_much / ((level >= 7) ? 4 : 2); if ((type_of_attacker == 1) && ((level = get_prot_level(which_pc,60)) > 0)) how_much = how_much / ((level >= 7) ? 4 : 2); if ((type_of_attacker == 9) && ((level = get_prot_level(which_pc,61)) > 0)) how_much = how_much / ((level >= 7) ? 4 : 2); To Thuryl : Quote: Try creating a custom undead/demon monster with a 20d1 attack and having it attack another custom monster with 50 armour. Its attacks will do 20 damage every time. Indeed, you're right. The armor is not checked when an undead or a demon attacks another monster; as you said, it is when a pc is attacked though. Click to reveal.. (proof) file SPECIALS.cpp, function damage_monst() [...] r1 = get_ran(1,0,(victim->m_d.armor * 5) / 4); //get a random number between 0 and 5/4 victim monster armor r1 += victim->m_d.level / 4; // add the victim monster level divided by 4 to this number if (dam_type == 0) // if the damage type is 0 (normal) (undead is 6 and demon 7) how_much -= r1; // substract the number to the damage done Chokboyz
  11. Actually, it does seems, from the code, that undead and demons have the same chance to hit you (or another monster) than others creatures and does not augmented damages (the undead or demon type is used only to check for undead/demons protecting items) ... It was a quick glance though, so i may have overlooked something. Quote: Just thought I should say that before anyone changes it, since nobody else seems to bring this up when people complain about it. Won't changes anything likes that In fact, the main goal is to produce a stable (relatively) bug-free release (hopefully cross-platform) before changing anything radical. Quote: Permanent Martyr's Shield is the other way around You are right. From the code, when monster attacks monster (hand-to-hand), the following effects only are checked : is attacker blessed/cursed ? is attacker webbed ? is target blessed/cursed ? is target sleepy? is target paralysed? poisoned monster weapon ? undead slowing effect web target effect put target to sleep dumbfound target paralyse target acid touch freezing touch death touch No disease, no stoning, etc ... Quote: The biggest single problem is the way the Scenario Editor does not use custom graphics in its zoom out view, it is a wonder Jeff never fixed this himself. I will give it a try, but i won't promise anything ... after all, you're the expert of the Character/Scenario Editor here Chokboyz
  12. You're right there is a typo in my post. The correct line is 480 in TEXT.cpp. I've checked the others, they should be right. And i'm using Ormus 32-bit source code (the windows official one is a nightmare to compile). Thanks, Chokboyz
  13. Another bug fix post. Note: when i say a bug is present in the mac version, i refer to the latest sources of OBoE on Khoth's site (but i may be wrong since i can't compile or even test mac version of the game ...) (Robsta)Fix masking on custom item graphics in the inventory? (present on windows, already fixed on mac) First, in place_item_button() (TEXT.cpp), the function rect_draw_some_item() (GRAPHUTL.cpp) is called with the transparency set to wrong. Replace line 480 in TEXT.cpp rect_draw_some_item (spec_scen_g, from_rect, item_stats_gworld, to_rect, 0, 0); by rect_draw_some_item (spec_scen_g, from_rect, item_stats_gworld, to_rect, 1, 0); Second, the called function is buggy for custom items (on windows only, as far as i can tell). In fact, the hdcMem2 object is given dest_rect size but later given the scr_rect size (smaller) which results in gibberish graphic in the items screen. The problem is transparent with base objects because the dest_rect and src_rect are the same size. Custom objects are on the other hand of different dest and src sizes, thus the function needs to be fixed. Replace lines 106-109 in GRAPHUTL.cpp Click to reveal.. StretchBlt(hdcMem3,dest_rect.left,dest_rect.top,dest_rect.right - dest_rect.left, dest_rect.bottom - dest_rect.top, hdcMem2,0,0,src_rect.right - src_rect.left, src_rect.bottom - src_rect.top,SRCAND); by Click to reveal.. StretchBlt(hdcMem3,dest_rect.left,dest_rect.top,dest_rect.right - dest_rect.left, dest_rect.bottom - dest_rect.top, hdcMem2,0,0,dest_rect.right - dest_rect.left, dest_rect.bottom - dest_rect.top,SRCAND); Note that the same error is done later in the file (lines 145-148), and should be fixed too. (CommonGenius)Apparently the Defence skill rather than the Thrown Missiles skill is checked when firing missile weapons. (present on windows, present on mac) That is absolutely right. In COMBAT.cpp, line 1171 : skill = (overall_mode == 12) ? adven[current_pc].skills[7] : adven[current_pc].skills[8]; should be replace by skill = (overall_mode == 12 ? adven[current_pc].skills[7] : adven[current_pc].skills[6]; Now, Thissa, Adrianna, Feodoric and Michael should be able to make something out of the points they have by default in Thrown Missiles. "Sleeping Ray" trap wasn't working (present on windows, present on mac) I found this bug while completing the CONSTS.h file in Ormus' build : the "Sleep Ray" trap (trap number 5 ; it actually paralyses the pc if he fails to disarm it) wasn't working. The culprit is a check done in the beginning of the class pc_record_type::runTrap() in the file PC.cpp (it is the function run_trap() in BLXTOWN_SPC.c in the mac sources), thats return TRUE if the called trap is either 5 ("sleep ray" trap) or 6 (oddly, an undefined trap). A fix is to simply replace line 92 in file PC.cpp (it is line 153 in BLXTOWN_SPC.c file for mac) if ((trap_type == 5) || (trap_type == 6)) by if (trap_type == 6) Petrification touch causes disease (Ishad Nha, others ?) (present on windows, present on mac) This one is a little different in nature. The petrification touch is actually checked in the cause disease effect in the function monster_attack_pc(), line 2011 (2307 on mac), in file COMBAT.cpp (it is the monster spec_skill 30) : if (((attacker->m_d.spec_skill == 25) || (attacker->m_d.spec_skill == 30)) Fixing it requires two things on bot mac and : First, replace the previous line if (((attacker->m_d.spec_skill == 25) || (attacker->m_d.spec_skill == 30)) by if ((attacker->m_d.spec_skill == 25) (note that it is a two lines wide check, hence the extra parenthesis ; this should be done on either the mac and the windows version) Then, create a petrificating touch effect in the function (after the disease effect for example). Click to reveal.. (Windows Version) // Petrification touch if (attacker->m_d.spec_skill == 30 && (adven[target].hasAbilEquip(49) == 24) && (get_ran(1,0,20) + adven[target].level / 4 + adven[target].status[1]) <= 14) { add_string_to_buf(" Petrificating touch!"); print_buf(); adven[target].kill(4); // 4 being the stoned (petrified, duh!) status } or, Mac Version (pure guess for the kill_pc line, just by looking at the code : might needs some tweaking) Click to reveal.. (Mac Version) // Petrification touch if (attacker->m_d.spec_skill == 30 && (pc_has_abil_equip(target,49) == 24) && (get_ran(1,0,20) + adven[target].level / 4 + adven[target].status[1]) <= 14) { add_string_to_buf(" Petrificating touch!"); print_buf(); kill_pc(target,4); // 4 being the stoned (petrified, duh!) status } (Note : the hasAbilEquip(49) test is a check to see if the pc has some protection from petrification items equipped.) Why is this one a little different ? Because i had to make an arbitrary decision. In fact, as you can see in the code, each time the monster hits you, you have the same chance of being petrified then when a basilisk gazes at you. This should be discussed (after all, it isn't a ranged attack anymore). Finally a little completed CONSTS.h file for ormus' build tweakers out there : Click to reveal.. #ifndef _CONSTS_H #define _CONSTS_H /* This file contain numerous constans in form of #defines. Almost all of this constants cannot be changed because that would make the game work improperly. */ #define NUM_OF_PCS 6 #define INVALID_PC NUM_OF_PCS #define INVALID_TOWN 200 #define NUM_OF_BOATS 30 #define NUM_OF_HORSES 30 #define SFX_SMALL_BLOOD 1 #define SFX_MEDIUM_BLOOD 2 #define SFX_LARGE_BLOOD 4 #define SFX_SMALL_SLIME 8 #define SFX_BIG_SLIME 16 #define SFX_ASH 32 #define SFX_BONES 64 #define SFX_RUBBLE 128 /* stuff done flags */ #define SDF_IS_PARTY_SPLIT 304][0 #define SDF_PARTY_SPLIT_X 304][1 #define SDF_PARTY_SPLIT_Y 304][2 #define SDF_NO_INSTANT_HELP 306][4 // boolean /* overall mode */ #define MODE_OUTDOORS 0 #define MODE_TOWN 1 #define MODE_TALK_TOWN 2 // looking for someone to talk #define MODE_COMBAT 10 #define MODE_FIRING 12 // firing from bow or crossbow #define MODE_THROWING 13 // throwing missle #define MODE_DROPPING 15 #define MODE_TALKING 20 #define MODE_SHOPPING 21 #define MODE_LOOK_OUTDOORS 35 // looking at something #define MODE_LOOK_TOWN 36 #define MODE_LOOK_COMBAT 37 /* adven.main_status */ //complete #define MAIN_STATUS_ABSENT 0 // absent, empty slot #define MAIN_STATUS_ALIVE 1 #define MAIN_STATUS_DEAD 2 #define MAIN_STATUS_DUST 3 #define MAIN_STATUS_STONE 4 #define MAIN_STATUS_FLED 5 #define MAIN_STATUS_SURFACE 6 // fled to surface? #define MAIN_STATUS_WON 7 /* main status modifiers */ #define MAIN_STATUS_SPLIT 10 // split from party /* adven.skills */ //complete #define SKILL_STRENGTH 0 #define SKILL_DEXTERITY 1 #define SKILL_INTELLIGENCE 2 #define SKILL_EDGED_WEAPONS 3 #define SKILL_BASHING_WEAPONS 4 #define SKILL_POLE_WEAPONS 5 #define SKILL_THROWN_MISSILES 6 #define SKILL_ARCHERY 7 #define SKILL_DEFENSE 8 #define SKILL_MAGE_SPELLS 9 #define SKILL_PRIEST_SPELLS 10 #define SKILL_MAGE_LORE 11 #define SKILL_ALCHEMY 12 #define SKILL_ITEM_LORE 13 #define SKILL_DISARM_TRAPS 14 #define SKILL_LOCKPICKING 15 #define SKILL_ASSASSINATION 16 #define SKILL_POISON 17 #define SKILL_LUCK 18 /* adven.traits */ //complete #define TRAIT_TOUGHNESS 0 #define TRAIT_MAGICALLY_APT 1 #define TRAIT_AMBIDEXTROUS 2 #define TRAIT_NIMBLE 3 #define TRAIT_CAVE_LORE 4 #define TRAIT_WOODSMAN 5 #define TRAIT_GOOD_CONST 6 #define TRAIT_HIGHLY_ALERT 7 #define TRAIT_EXCEPTIONAL_STRENGTH 8 #define TRAIT_RECUPERATION 9 #define TRAIT_SLUGGISH 10 #define TRAIT_MAGICALLY_INEPT 11 #define TRAIT_FRAIL 12 #define TRAIT_CHRONIC_DISEASE 13 #define TRAIT_BAD_BACK 14 /* adven.race */ //complete #define RACE_HUMAN 0 #define RACE_NEPHIL 1 #define RACE_SLITH 2 /* adven.status*/ //complete - assign a positive value for a help pc effect, a negative for harm pc #define STATUS_POISONED_WEAPON 0 #define STATUS_BLESS 1 #define STATUS_POISON 2 #define STATUS_HASTE 3 #define STATUS_INVULNERABLE 4 #define STATUS_MAGIC_RESISTANCE 5 #define STATUS_WEBS 6 #define STATUS_DISEASE 7 #define STATUS_INVISIBLE 8 //sanctuary #define STATUS_DUMB 9 #define STATUS_MARTYRS_SHIELD 10 #define STATUS_ASLEEP 11 #define STATUS_PARALYZED 12 #define STATUS_ACID 13 /* damage type*/ /* used as parameter to some functions */ #define DAMAGE_WEAPON 0 #define DAMAGE_FIRE 1 #define DAMAGE_POISON 2 #define DAMAGE_MAGIC 3 #define DAMAGE_UNBLOCKABLE 4 //from the source files - the display is the same as the magic one (damage_monst in SPECIALS.cpp) #define DAMAGE_COLD 5 #define DAMAGE_UNDEAD 6 //from the source files - the display is the same as the weapon one #define DAMAGE_DEMON 7 //from the source files - the display is the same as the weapon one // 8 and 9 aren't defined : doesn't print any damage. According to the source files the 9 is DAMAGE_MARKED though. Wrong ? #define DAMAGE_MARKED 10 // usage: DAMAGE_MARKED + damage_type #define DAMAGE_NO_PRINT 30 // usage: DAMAGE_NO_PRINT + damage_type /* trap type */ /* used in pc_record_type::runTrap(...) */ #define TRAP_RANDOM 0 #define TRAP_BLADE 1 #define TRAP_DART 2 #define TRAP_GAS 3 // poisons all #define TRAP_EXPLOSION 4 // damages all => uses c_town.difficulty rather than trap_level to calculates damages (and even c_town.difficulty /13). #define TRAP_SLEEP_RAY 5 // 6 isn't defined (see runtrap classe in PC.cpp #define TRAP_DRAIN_XP 7 #define TRAP_ALERT 8 // makes town hostile #define TRAP_FLAMES 9 // damages all => uses trap_level (*5) to calculates damages. #define TRAP_DUMBFOUND 10 //dumbfound all #define TRAP_DISEASE 11 #define TRAP_DISEASE_ALL 12 #endif Chokboyz
  14. (ADoS)Fix recording of dialogue nodes which result from a special node sequence. (fixed) This was a simple typo in the INFODLGS.cpp file. In function put_talk(), line 1059, replace the line : party.talk_save[store_page_on].str2 - 2000 + 20,(char *) place_str); by : party.talk_save[store_page_on].str2 - 2000,(char *) place_str); Actually, only the second part of the message wasn't properly read (but was properly written). The random results could range from stranges symbols ("empty" pointed element in the array) to previously recorded dialogues. Interestingly, there is a test in the code preventing you from recording the Don't Understand Response ... Unfortunately, I haven't been able to check if this bug was present in the Mac version of BoE. Should it be the case, the fix would be the same. Chokboyz
  15. Ok, i will browse the last pages of the topic and see what has already been done. Will also checks this scenario format changes you mentioned ... Thanks for the compiled list anyway ... Quote: I'll remove them when they are fixed in both Mac and Windows versions and an executable with the fixes is released. Fair enough ... Chokboyz
  16. You are absolutely right, there are two major flaws in the previous code : first, assuming that only scenario loading needs to be in the executable directory (why i forget loading of game currently in a scenario, i don't know) and second, not initialising an array (in Get_Path) that gets check later ... Here is the solution i propose : as soon as the pointer to the savefile is set (while loading or saving), return to the executable directory (so that the program behaves as intended); and initialise the file_path[256] array to "" to prevent random memory to be read in it. Below, the functions that need to be changed in the FILEIO.ccp(use a clean copy of FILEIO.cpp to avoid leftovers; as usual changes from the original file are in cyan) : Click to reveal.. in FILEIO.cpp void Get_Path(char* path){ char file_path[256]=""; // initialization GetModuleFileName(NULL,file_path,256); // get path to the executable int i=255; // initialize the first while loop while(file_path != '\\') { i--; // find the last '\' in the path to the executable } // in order to get rid of 'blades of exile.exe' int j=0; // initialize the second loop for(j=0;j<i+1;j++) { path[j]=file_path[j]; // transfert the path to argument string } path[i+1]='\0'; // close the argument string after the last '\' } Click to reveal.. void load_file() { HANDLE file_id; short i,j,k; Boolean town_restore = FALSE; Boolean maps_there = FALSE; DWORD dwByteRead; UINT count; char *party_ptr; char *pc_ptr; short flag; Boolean in_scen = FALSE; short flags[3][2] = {{5790,1342}, // slot 0 ... 5790 - out 1342 - town {100,200}, // slot 1 100 in scenario, 200 not in {3422,5567}}; // slot 2 ... 3422 - no maps 5567 - maps ofn.hwndOwner = mainPtr; ofn.lpstrFile = szFileName; ofn.lpstrFileTitle = szTitleName; ofn.Flags = 0; if (GetOpenFileName(&ofn) == 0) return; file_id = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (file_id == INVALID_HANDLE_VALUE) return; char file_path[256]=""; // returns to executable directory Get_Path(file_path); SetCurrentDirectory(file_path); for (i = 0; i < 3; i++) { if (ReadFile(file_id, &flag, sizeof(short), &dwByteRead, NULL) == FALSE) { CloseHandle(file_id); return; } if ((flag != flags[0]) && (flag != flags[1])) { CloseHandle(file_id); FCD(1063,0); return; } if ((i == 0) && (flag == flags[1])) town_restore = TRUE; if ((i == 1) && (flag == flags[0])) in_scen = TRUE; if ((i == 2) && (flag == flags[1])) maps_there = TRUE; } // LOAD PARTY [...] Click to reveal.. void save_file(short mode) //mode 0 - normal 1 - save as { HANDLE file_id; Boolean town_save = FALSE; short i, j; DWORD count, bytes, dwByteRead; short flag; short *store; party_record_type *party_ptr; setup_save_type *setup_ptr; pc_record_type *pc_ptr; current_town_type *town_ptr; char *party_encryptor; if ((in_startup_mode == FALSE) && (is_town())) town_save = TRUE; ofn.hwndOwner = mainPtr; ofn.lpstrFile = szFileName; ofn.lpstrFileTitle = szTitleName; ofn.Flags = OFN_OVERWRITEPROMPT; if ((mode == 1) || (in_startup_mode == TRUE)) { if (GetSaveFileName(&ofn) == 0) return; } if (strcmpi(&ofn.lpstrFile[ofn.nFileExtension], "savx") == 0) { /* for experimental formats of save-game files */ } file_id = CreateFile(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (file_id == INVALID_HANDLE_VALUE) return; char file_path[256]=""; // returns to executable directory Get_Path(file_path); SetCurrentDirectory(file_path); store = &flag; flag = (town_save == TRUE) ? 1342 : 5790; [...] and it should works ... Thanks for pointing that out, Chokboyz
  17. Quote: One way around this is to just show the entire function. Will do that from now on. Quote: the scenario icons problem was cured by restoring the original text of dlgutils.cpp, may have only been a problem for me. Didn't have any icons problem here, so it seems, indeed, to be an altered DLGUTILS.cpp file ... (in fact, i didn't changed a single line of code in this file) Nice to see it compiled and worked; this should finally fix the custom scenario selection bug. I also fixed the Conceal Ability flag (and made some cosmetic changes), only to found you had already fixed it (amongt others things, thanks to your hardwork). Is there an updated list of bug to fix ? (Compiled Suggestion List is apparently not) Chokboyz
  18. Ok, i see; there are leftovers from the previous "fix" ... My bad, i should have added that previous changes needed to be removed. You must remove the three lines (those with comments) right after SendMessage(listbox,LB_GETTEXT,i,(LONG) (LPSTR) filename2); and revert the last one by sprintf((char *) filename,"scenarios/%s",filename2); Here is my load_scen_headers() function if you just want to copy/paste Click to reveal.. void build_scen_headers() { short i; short cur_entry = 0; HWND listbox; WORD count; char filename[256],filename2[256]; for (i = 0; i < 100; i++) scen_headers.flag1 = 0; listbox = CreateWindow("listbox", NULL, WS_CHILDWINDOW, // 3 0,0,0,0, // 7 mainPtr, // 8 (HMENU) 1, // 9 (HINSTANCE) GetWindowLong(mainPtr, GWL_HINSTANCE), // 10 NULL); // 11 char file_path[256]=""; // these are the only three lines added to the original function Get_Path(file_path); SetCurrentDirectory(file_path); SendMessage(listbox,LB_DIR,0x0,(LPARAM) (LPCTSTR) "scenarios/*.exs"); count = (WORD) SendMessage(listbox,LB_GETCOUNT,0,0L); count = min(count,100); for (i = 0; i < count; i++) { SendMessage(listbox,LB_GETTEXT,i,(LONG) (LPSTR) filename2); sprintf((char *) filename,"scenarios/%s",filename2); if (load_scenario_header(filename,cur_entry) == TRUE) { // now we need to store the file name, first stripping any path that occurs // before it strcpy((char *) data_store2->scen_names[cur_entry],(char *) filename2); cur_entry++; } } DestroyWindow(listbox); } and it should works ... You may also want to check if you have updated the definition of Get_Path() as it doesn't do useless characters shifting in its the last definition. Hope it helps, Chokboyz P.S : Technically, the compiler was objecting that the path variable was nowhere defined. When you defined char* path; at the beginning of the function, you tell the compiler to create and reserve memory for a pointer named path. Unfortunately, pointers are not initialised (to NULL or whatever) in C, so it could point anywhere in the memory; hence the crash when Get_Path tries to write in the array it points to (incoming segmentation_fault).
  19. Strange, it compiles fine when i do ... What is the error message ? In which file/function does it occurs ? About the changes you made : void build_scen_headers() { short i; short cur_entry = 0; HWND listbox; WORD count; char filename[256],filename2[256]; void Get_Path(char* path); <= definition of the function Get_Path (should already be defined so should not compiled, checks if you declared the Get_Path function in your FILEIO.h) char* path; <= this is a pointer to an unspecified array, not initialized ? for (i = 0; i < 100; i++) scen_headers.flag1 = 0; Chokboyz
  20. Looks like the Conceal Ability flag had already been fixed by Ishad Nha ... I just assumed that the list was up-to-date, but doesn't seems so Originally Posted By: Celtic Minstrel Originally Posted By: Ishad Nha Yes, it does, line 153 of Blades.cpp. Moving it to the folder is not a big deal, it's a one-off action that takes ten seconds Yes, but it would be even better if the program could find the font regardless of whether it is in the font folder. If you really want the font to be loaded from the game directory, you just needs to register the font when initialising BoE and unregistering it when closing. For that, only two lines of codes are to be added in BLADES.cpp : Click to reveal.. void loadFonts() { AddFontResource("maidword.ttf"); // add font to the sytem font table font = CreateFont(12,0,0,0,0, 0,0,0, 0,0, 0,0,0,"MS Sans Serif"); small_bold_font = CreateFont(12,0,0,0,700, 0,0,0, 0,0, 0,0,0,"MS Sans Serif"); italic_font = CreateFont(12,0,0,0,700, 1,0,0, 0,0, 0,0,0,"MS Sans Serif"); underline_font = CreateFont(12,0,0,0,0, 0,1,0, 0,0, 0,0,0,"MS Sans Serif"); bold_font = CreateFont(14,0,0,0,700, 0,0,0, 0,0, 0,0,0,"MS Sans Serif"); tiny_font = font; fantasy_font = CreateFont(22,0,0,0,0, 0,0,0, 0,0, 0,0,0,"MaidenWord"); if (fantasy_font == NULL) { fantasy_font = CreateFont(22,0,0,0,0, 0,0,0, 0,0, 0,0,0,"MS Sans Serif"); } } and, at the end of the winmain() function Click to reveal.. int WINAPI WinMain(...) [...] delete data_store2; delete data_store; RemoveFontResource("maidword.ttf"); // remove the font from the system font table FreeLibrary((HMODULE) boeSoundsDLL); return msg.wParam; } and BoE will find and use the MaidenWord font (if it fails to find "maidword.ttf" it uses MS Sans Serif instead). Chokboyz
  21. Hello, seeing in the Compiled Suggestion List that the Conceal_Ability flag was broken, i browse the code a bit and found that it wasn't hard to fix. So i did. - What was wrong : In the Scenario Editor, giving an item the Conceal_Ability flag, add 32 to its unsigned char item_properties (putting sixth bit to 1 : xx1xxxxx with x=0 or 1). No problem with the editor then. The problem was that nothing was done with this value in the game code (it wasn't even defined). - A fix : First we defines the Conceal_ability flag in ITEM.h : Click to reveal.. #ifndef _ITEM_H #define _ITEM_H #include "location.h" /* item_properties: */ /* 0000 0001 identified 0000 0010 someone's property 0000 0100 magic 0000 1000 contained in sth 0001 0000 cursed 0010 0000 concealed 0100 0000 <not used> 1000 0000 <not used> */ #define ITEM_PROP_IDENTIFIED 1 #define ITEM_PROP_PROPERTY 2 #define ITEM_PROP_MAGIC 4 #define ITEM_PROP_CONTAINED 8 #define ITEM_PROP_CURSED 16 #define ITEM_PROP_CONCEALED 32 //defines the conceal_ability flag struct item_record_type { short variety, item_level; char awkward, bonus, protection, charges, type, magic_use_type; unsigned char graphic_num,ability, ability_strength, type_flag, is_special,a; short value; unsigned char weight, special_class; location item_loc; char full_name[25], name[15]; unsigned char treas_class, item_properties, reserved1, reserved2; /* functions */ bool isIdent() const; /* is identified ? */ bool isMagic() const; /* is magic ? */ bool isContained() const; /* is contained in sth ? */ bool isCursed() const; /* is cursed ? */ bool isProperty() const; /* is someones property? */ bool isConcealed() const; /* is the item ability to be concealed ? */ }; #endif then we defines in ITEM.cpp the isConcealed() function we've just declared : Click to reveal.. [...] bool item_record_type::isConcealed() const { if (item_properties & ITEM_PROP_CONCEALED) return true; else return false; } [...] finally we modifies in INFOGLGS.cpp the function put_item_info() which creates and display items info : Click to reveal.. [...] if (s_i.ability > 0) {//// GetIndString(desc_str,23,s_i.ability + 1); cd_set_item_text(998,12,(char *) desc_str); } if (s_i.isConcealed()){cd_set_item_text(998,12,"???");} //check if the item ability is to be concealed and print "???" in ability if so else{ GetIndString(desc_str,23,s_i.ability + 1); //else it display the item ability as usual cd_set_item_text(998,12,(char *) desc_str); //note : common items weren't displaying the "No ability" string. It is restored here. } [...] and the Conceal_Ability flag will works. Not part of the fix, a little cosmetic change that could be made is to display "???" in ability when the item is not identified (it actually displays nothing). Here is the code to do so (always in INFODLGS.cpp) : Click to reveal.. [...] if (s_i.isIdent() == false) { cd_set_item_text(998,3, s_i.name); cd_set_item_text(998,12, "???"); // cosmetic change, display ??? in ability when the item isn't identified return; } [...] Here it goes, Chokboyz
  22. Hello, i've finally understood the custom scenarios loading mechanics and found what was wrong. - "Technical" considerations : First of all, to load a scenario, BoE only needs the variable party.scen_name (a string which contains the "name_of_the_scen.exs") to be set. This variable is stored and read in savefile (cf in FILEIO.cpp, in the function save_file() : WriteFile(file_id, party.scen_name, 256, &dwByteRead, NULL); and in the load_file() function : ReadFile(file_id, party.scen_name, 256, &dwByteRead, NULL);) and that explains why while in a scenario, loading works smoothly. Second, concerning the prefabricated scenarios, the party.scen_name is hardcoded (in BLADES.cpp, handle_startup_press() switch case 3) and that's why, while custom scenario loading is broken, prefabricated ones works. Clicking the custom scenario button, call the pick_a_scen() function (in BLADES.cpp, handle_startup_press() switch case 4) which try to return the number of the scenario in the list of all founded scenario. Right after initializing variables, the pick_a_scen() function calls the build_scen_headers() function which creates a listbox and tries to populates it with all "/scenarios/*.exs" founded in the current directory (relative path). And here is where the bug occurs. - The bug : Trying to populate the listbox, build_scen_headers() looks in current folder which is ... savefile folder. Indeed, in load_file() (resp save_file()) the function GetOpenFileName() (resp GetSaveFileName()) is used and change the current directory to the one of the selected file permanently. Having to load a party to pick a custom scenario, the build_scen_headers() is then looking in the wrong savefile folder to populate the listbox. - A note of interest : The function build_scen_file_name() would suffers from the same bug, except the first 8 lines of the code are a fix to avoid using current directory. Oddly enough, this fix has not been used for build_scen_headers, preventing it to work as intended. Browsing the original sources, it seems this bug is present since the original release of the sources. Could it actually be that the "custom scenarios" button never worked ? It's also worth to note that the fix in build_scen_file_name() use the global variable file_path_name[256] defined in WinMain() which is actually the full path to the executable. Since the scenario loading functions are seldom called, it could be better (memory wise) to actually replace this global variable by a call to a function (it's what i do in my proposed solution). - Proposition of solution : Here is a possible fix : Legend : new_code, old_code, deleted_code First we need to (re)define a function to get the current path to the executable. The previous Get_Path() is here updated, hopefully cleaner (thanks again to nerubianlord for pointing out that '\' characters were also working. Note that file_path size is now 256 instead of MAX_PATH to comply with original code.) Click to reveal.. In FILEIO.h : void Get_Path(char* path); In FILEIO.cpp : void Get_Path(char* path){ char file_path[256]; // initialization GetModuleFileName(NULL,file_path,256); // get path to the executable int i=255; // initialize the first while loop while(file_path != '\\') { i--; // find the last '\' in the path to the executable } // in order to get rid of 'blades of exile.exe' int j=0; // initialize the second loop for(j=0;j<i+1;j++) { path[j]=file_path[j]; // transfert the path to argument string } path[i+1]='\0'; // close the argument string after the last '\' } then we correct the current directory in build_scen_headers() (in FILEIO.cpp) : Click to reveal.. [...] listbox = CreateWindow("listbox", NULL, WS_CHILDWINDOW, // 3 0,0,0,0, // 7 mainPtr, // 8 (HMENU) 1, // 9 (HINSTANCE) GetWindowLong(mainPtr, GWL_HINSTANCE), // 10 NULL); // 11 char file_path[256]=""; Get_Path(file_path); // get path to the directory the executable is in SetCurrentDirectory(file_path); // change the current directory to the right one SendMessage(listbox,LB_DIR,0x0,(LPARAM) (LPCTSTR) "scenarios/*.exs"); [...] and the "custom scenarios" button and listing should now works. The next changes are not part of the fix, but an attempt to make a cleaner code. We replace the fix in build_scen_file_name() (in FILEIO.cpp) by a simple call to Get_Path() : Click to reveal.. void build_scen_file_name (char *file_n) { short i,last_slash = -1; for (i = 0; i < 256; i++) if ((file_path_name == 92) || (file_path_name == '/')) last_slash = i; if (last_slash < 0) { sprintf((char *) file_n,"scenarios/%s",party.scen_name); return; } char file_path[256]; Get_Path(file_path); //get executable directory strcpy(file_n,file_path); // copy the executable directory. file_n += last_slash + 1; sprintf((char *) file_n,"scenarios/%s",party.scen_name); } Finally, we get rid of the now useless global variable file_path_name[256] (yes, it was only used by build_scen_file_name()) : Click to reveal.. In BLADES.cpp : int WINAPI WinMain (...) [...] GetModuleFileName(hInstance,file_path_name,256); [...] In GLOBVAR.cpp : [...] char file_path_name[256]; [...] In GLOBVAR.h : [...] extern char file_path_name[256]; [...] Hope it helps, Chokboyz
  23. Addentum : seems like i forgot to say something important ... While the program looks for "scenarios" folder in the same folder as the loaded savefile, it tries to load the actual scenario from the scenario folder located in the Blade of Exile directory ... So the quick "fix" mentionned above means : copy the "scenarios" folder to these two locations (savefile folder and blade of exile folder). It seems i'm not the first to notice that (although it is not necessary My Documents/Scenarios but the folder your savefile is in), Originally Posted By: UA Looks like scenarios need to be in both the Documents\Scenarios directory and the Blades of Exile\Scenarios directory. Ormus's build is building the list of scenarios from Documents\Scenarios and trying to load scenarios from Blades of Exile\Scenarios. but i should add it anyway ...
  24. Thanks for your response and hardwork ... Concerning the custom scenario bug, i think i've found what causes it and discuss a possible fix at this topic http://www.ironycentral.com/forum/ubbthreads.php?ubb=showflat&Number=160765#Post160765 Hope it works Chokboyz
  25. Update : why the bug happens has been found, see posts below. Hello, for what i have been able to understand (and test) custom scenario selection in the Win32 build of BoE is broken. Browsing the source of the build Ormus has kindly released under GNU GLP2, i managed to (hopefully) found a fix ... First of all, i'm not a programmer, so my code is not of the highest standard. Feel free to improve it - What is wrong ? In the FILEIO.cpp, the problem lies in the void build_scen_headers() function : The parameters "scenarios/*.exs" in the line SendMessage(listbox,LB_DIR,0x0,(LPARAM) (LPCTSTR) "scenarios/*.exs"); and a few lines under, the parameter "scenarios/%s" in sprintf((char *) filename,"scenarios/%s",filename2); are leaving the program clueless. In fact, loading a savefile change the current directory to the one the savefile is. You can test it using the GetCurrentDirectory function or simply by copying the scenarios folder in the same directory as your savefile (usually My Documents) and scenarii should work. What is happening is that the program try to find the "scenarios" directory in the folder your savefile is instead of the BoE folder. - How to fix it ? A quick "fix" would be to put your "scenarios" folder in the same folder as your savefile. Not properly a fix, it saves from having to recompile the code. To fix the program itself, so it would look for the "scenarios" folder in the BoE folder, requires to modify the FILEIO.CPP file. First we need a way to get the path to the executable "blades of exile.exe". I didn't find a function for it in the source code (not certain about that) so here is a proposition of such a fonction : Click to reveal.. void Get_Path(char* path){ char szDirectory[MAX_PATH] = ""; //initialization GetModuleFileName(NULL,szDirectory,sizeof(szDirectory)-1); //get the executable full path int i=MAX_PATH; // initialize the first while loop while(szDirectory != '\\') { i--; // find the last '\' in the path to the executable } // in order to get rid of 'blades of exile.exe' szDirectory[i+1]='\0'; // close the string after the last '\' int j=0; // initialize the second loop for(j=0;j<i+1;j++) { if (szDirectory[j] == '\\') { szDirectory[j]='/'; // replace the '\' by '/' in the path } // since BoE needs '/' } for(j=0;j<i+2;j++) { path[j]=szDirectory[j]; // transfert the path to argument string } } Then we need to modify the paramaters in the void build_scen_headers() function : Replace SendMessage(listbox,LB_DIR,0x0,(LPARAM) (LPCTSTR) "scenarios/*.exs"); by Click to reveal.. char path[MAX_PATH]; //initialization Get_Path(path); // get the path to the executable strcat(path,"scenarios/*.EXS"); // concatenate the rest of the string SendMessage(listbox,LB_DIR,0x0, (LONG) path ); // send the message with correct path and replace, a few line under, sprintf((char *) filename,"scenarios/%s",filename2); by Click to reveal.. Get_Path(path); // get the path to the executable strcat(path,"scenarios/"); // concatenate the strcat(path,filename2); // rest of the string sprintf((char *) filename,path); // sprintf with correct path and it should work : the program would now look for scenarios in the "[path_to_BoE]/scenarios" folder. This fix has been tested with the latest Ormus' source code and worked. (thanks to nerubianlord for pointing out that the file extension was zip and not rar, allowing me to get the files) For modularity, the path to the scenario folder could also be stored and read in the .ini file, thus being editable without having to recompile the sources. Hope it helps, Chokboyz
×
×
  • Create New...