The reason it's triggering when even one items is present is because 1) ItemEnteredTrigger triggers, and 2) The item is indeed in the database, so 3) The text is displayed on the first item.
You might want to check and see if this code works:
TriggerRegisterForItems(TRIGGER_HIB_ENIGMA02_Optable);
DB_Enigma02_bodyparts(ITEM_HIB_ENIGMA02_BODYPART1);
DB_Enigma02_bodyparts(ITEM_HIB_ENIGMA02_BODYPART2);
DB_Enigma02_bodyparts(ITEM_HIB_ENIGMA02_BODYPART3);
IF
ItemEnteredTrigger(_Item,TRIGGER_HIB_ENIGMA02_Optable,_Player)
AND
DB_Enigma02_bodyparts(_Item)
THEN
PopulateTempList();
DisplayWhenAllItemsArePresent();
RemoveTempTrigger();
PROC
PopulateTempList()
AND
DB_Enigma02_bodyparts(_Item)
THEN
NOT DB_Enigma02_bodyparts(_Item);
DB_TempList(_Item);
PopulateTempList();
NOT DB_TempList(_Item);
DB_Enigma02_bodyparts(_Item);
IF
DB_TempList(_Item)
AND
ItemIsInTrigger(_Item, ITEM_HIB_ENIGMA02_Optable, 0)
THEN
DB_NotInTrigger(1);
PROC
DisplayWhenAllItemsArePresent()
AND
NOT DB_NotInTrigger(1)
THEN
CharacterDisplayText(CHARACTER_CHARACTER_Player1, "PENNY_01");
PROC
RemoveTempTrigger()
AND
DB_NotInTrigger(_Num)
THEN
NOT DB_NotInTrigger(_Num);
RemoveTempTrigger();
If I wrote the code correctly (read: I haven't tested this), then it should be making use of Recursive PROCs to iterate through the list of items and checking whether they are in the trigger, and flagging it if they're not. Then it displays the text if it wasn't flagged.